当前位置:首页>编程知识库>后端开发知识>你能谈谈Java中 synchronized 对象锁和类锁的区别
你能谈谈Java中 synchronized 对象锁和类锁的区别
阅读 1
2020-07-22
synchronized 加到 static 方法前面是给class 加锁,即类锁;而synchronized 加到非静态方法前面是给对象上锁。
这两者的区别我用代码来演示下

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

Task2 中定义三个方法 doLongTimeTaskAdoLongTimeTaskB是类锁,而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
可以看出由于 doLongTimeTaskAdoLongTimeTaskB都是类锁,即同一个锁,所以 AB是按顺序执行,即同步的。而C是对象锁,和A/B不是同一种锁,所以CAB是 异步执行的。(ABC代指上面的3中方法)。
更多面试题,欢迎
我们知道对象锁要想保持同步执行,那么锁住的必须是同一个对象。下面就修改下上面的来证明:
Task2.java不变,修改ThreadAThreadB 如下:
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
从结果看来,对象锁锁的对象不一样,分别是mTaskamTaskb,所以线程A和线程B调用 doLongTimeTaskC 是异步执行的。
但是,类锁可以对类的所有对象的实例起作用。只需修改ThradAThreadBmain 方法不做改变,修改如下:
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。也就是说,类锁对所有的该类对象都能起作用。

总结:


如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是两种不同的锁。

类锁对该类的所有对象都能起作用,而对象锁不能。
作者:小猪快跑22
blog.csdn.net/zhujiangtaotaise/article/details/55509939
? ~
以上数据来源于网络,如有侵权,请联系删除。
评论 (0)