当前位置:   article > 正文

举例说明Java中synchronize对象锁和类锁有什么区别?_synchronized 实例和类的区别

synchronized 实例和类的区别

  • 刚学到这里的时候很困惑;只是简单知道:1、synchronized 加到 static 方法前面是给class 加锁,即类锁;2、而synchronized 加到非静态方法前面是给对象上锁,即对象锁。
  • 下面我就从代码的角度演示一下二者不同的现象。

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

  • 创建一个类Task2,在其中定义三个方法 doLongTimeTaskA和doLongTimeTaskB是类锁,
  • 而doLongTimeTaskC是对象锁。
  • 再创建3个线程,每个线程中调用调用该类对象锁和类锁的方法。
  • 在main函数中执行abc三个线程的代码。依次调用。
public class Task2 {
        public synchronized static void doLongTimeTaskA() {
            System.out.println("name = " + Thread.currentThread().getName() + ", begain ,"+ new Date());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

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

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

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

        public synchronized void doLongTimeTaskC() {

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

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

        }

    static class ThreadA extends Thread{

        private Task2 mTask2;

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

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

    static class ThreadB extends Thread{

        private Task2 mTask2;

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

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

    static class ThreadC extends Thread{

        private Task2 mTask2;

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

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

    public static void main(String[] args) {
        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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 执行的结果如下:

  • name = A, begain ,Sat Jun 11 09:45:49 CST 2022

  • name = C, begain ,Sat Jun 11 09:45:49 CST 2022

  • name = C, end ,Sat Jun 11 09:45:50 CST 2022

  • name = A, end ,Sat Jun 11 09:45:50 CST 2022

  • name = B, begain ,Sat Jun 11 09:45:50 CST 2022

  • name = B, end ,Sat Jun 11 09:45:51 CST 2022

  • 大家在跑的时候可以多跑几个例子,因为并不是每次跑该程序的结果都是一样的

  • 多跑几次结合数据我们可以发现由于doLongTimeTaskA方法和doLongTimeTaskB方法都是用static修饰的synchronize类锁,即同一个锁,所以 A和B是按顺序执行(类的层面上应该是整个进程唯一的),即同步的。

  • 而doLongTimeTaskC是对象锁,和A/B不是同一种锁,所以C和A、B是 异步执行的。(A、B、C代指上面的3中方法,A、B为类锁, C为对象锁即没有static修饰的方法)。

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

  • 在Task.java中修改ThreadA 和 ThreadB 中run代码,使ABC三个线程都调用doLongTimeTaskC()方法:
        @Override
        public void run() {
            mTask2.doLongTimeTaskC();
        }
  • 1
  • 2
  • 3
  • 4
  • 此时的main方法如下:
    public static void main(String[] args) {
        Task2 mTask2 = new Task2();
        Task2 mTask3 = new Task2();
        Task2 mTask4 = new Task2();
        ThreadA ta = new ThreadA(mTask2);
        ThreadB tb = new ThreadB(mTask3);
        ThreadC tc = new ThreadC(mTask4);

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

        ta.start();
        tb.start();
        tc.start();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 输出结果如下:
  • name = C, begain ,Sat Jun 11 10:25:20 CST 2022
  • name = B, begain ,Sat Jun 11 10:25:20 CST 2022
  • name = A, begain ,Sat Jun 11 10:25:20 CST 2022

  • name = B, end ,Sat Jun 11 10:25:25 CST 2022
  • name = C, end ,Sat Jun 11 10:25:25 CST 2022
  • name = A, end ,Sat Jun 11 10:25:25 CST 2022
  • 从结果来看,前三行先打印,表示三个线程同时异步执行,各自线程sleep后再打印后面的语句。
  • 从代码中看,这三个线程拿到的对象并不是一个对象,各自线程有各自的对象,而方法C又是对象锁。
  • 这个锁生效的前提是三个线程拿到的是同一个 Task2 对象。才能保证代码的同步执行。
    public static void main(String[] args) {
        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();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 可以看到线程A执行完自己run方法中调用的方法时,再去执行线程B,线程C 。
  • 第二种方法如果想要保证这三个线程中run方法中调用的方法同步执行的话,就将线程ABC三个线程中run方法中调用的doLongTimeTaskC改为doLongTimeTaskA或者doLongTimeTaskB,因为A,B是类锁,只要是这个类,就只能有一把锁。类锁对所有的该类对象都能起作用。
  • 不像对象,每个对象一把锁。
  • 两种方法实现三个线程同步。

3、总结

  • 1、如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是两种不同的锁。
  • 2、类锁对该类的所有对象都能起作用,而对象锁不能;对象锁只能对该对象起作用。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/292056
推荐阅读
相关标签
  

闽ICP备14008679号