面试官:你能谈谈Java中 synchronized 对象锁和类锁的区别

点击上方Java学习指南关注公众号

每天阅读Java干货文章


synchronized 加到 static 方法前面是给class 加锁,即类锁;而synchronized 加到非静态方法前面是给对象上锁。

这两者的区别我用代码来演示下

对象锁和类锁是不同的锁,所以多个线程同时执行这2个不同锁的方法时,是异步的。

在Task2 中定义三个方法 doLongTimeTaskA和doLongTimeTaskB是类锁,而doLongTimeTaskC是对象锁。

public class Task2 {

    public synchronized static void doLongTimeTaskA() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized static void doLongTimeTaskB() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized void doLongTimeTaskC() {

        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");

    }

三个线程的代码如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskB();
    }
}

class ThreadC extends Thread{

    private Task2 mTask2;

    public ThreadC(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main函数中执行代码如下:

        Task2 mTask2 = new Task2();
        ThreadA ta = new ThreadA(mTask2);
        ThreadB tb = new ThreadB(mTask2);
        ThreadC tc = new ThreadC(mTask2);

        ta.setName("A");
        tb.setName("B");
        tc.setName("C");

        ta.start();
        tb.start();
        tc.start();

执行的结果如下:

name = A, begain, time = 1487311199783
name = C, begain, time = 1487311199783
name = C, end, time = 1487311200784
name = A, end, time = 1487311200784
name = B, begain, time = 1487311200784
name = B, end, time = 1487311201784

可以看出由于 doLongTimeTaskA和doLongTimeTaskB都是类锁,即同一个锁,所以 A和B是按顺序执行,即同步的。而C是对象锁,和A/B不是同一种锁,所以C和A、B是 异步执行的。(A、B、C代指上面的3中方法)。

更多面试题,欢迎关注公众号 Java面试题精选

我们知道对象锁要想保持同步执行,那么锁住的必须是同一个对象。下面就修改下上面的来证明:

Task2.java不变,修改ThreadA 和 ThreadB 如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main方法如下:

 Task2 mTaska = new Task2();
 Task2 mTaskb = new Task2();
 ThreadA ta = new ThreadA(mTaska );
 ThreadB tb = new ThreadB(mTaskb );


 ta.setName("A");
 tb.setName("B");

 ta.start();
 tb.start();

结果如下:

name = A, begain, time = 1487311905775
name = B, begain, time = 1487311905775
name = B, end, time = 1487311906775
name = A, end, time = 1487311906775

从结果看来,对象锁锁的对象不一样,分别是mTaska , mTaskb,所以线程A和线程B调用 doLongTimeTaskC 是异步执行的。

但是,类锁可以对类的所有对象的实例起作用。只需修改ThradA 和 ThreadB,main 方法不做改变,修改如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
       //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

结果如下:

name = A, begain, time = 1487312239674
name = A, end, time = 1487312240674
name = B, begain, time = 1487312240674
name = B, end, time = 1487312241674

可以看出 在线程A执行完doLongTimeTaskA方法后,线程B才会获得该类锁接着去执行doLongTimeTaskA。也就是说,类锁对所有的该类对象都能起作用。

Java学习指南:一个只分享Java干货的公众号。

总结:

  1. 如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是两种不同的锁。
  2. 类锁对该类的所有对象都能起作用,而对象锁不能。

作者:小猪快跑22
blog.csdn.net/zhujiangtaotaise/article/details/55509939


END



如果文章对您有帮助,请您分享、点赞、在看,一波三连支持一下作者,非常感谢!

本文分享自微信公众号 - Java学习指南(gh_85b94beaede2)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/u/4097256/blog/4521516

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Apache Tomcat7、8、9(Java Web服务器)

Apache Tomcat7、8、9(Java Web服务器)

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。