zoukankan      html  css  js  c++  java
  • Java的类锁、对象锁和方法锁

    在Java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名“同步锁”。

    • 当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象锁。

    • 当用来修饰类和静态方法时,默认当前的类为锁的对象

    对象锁

    修饰在方法上时,多个线程调用同一对象同步方法时会阻塞,调用不同对象同步方法不会阻塞

    在多线程环境下,调用不同对象的同步方法:

    public class SynchronizedDemo {
    
        public synchronized void synTest(){
            int i = 5;
            while (i-- > 0){
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            SynchronizedDemo demo1 = new SynchronizedDemo();
            SynchronizedDemo demo2 = new SynchronizedDemo();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.obj3();
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo2.obj3();
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-0 : 4
    Thread-1 : 4
    Thread-0 : 3
    Thread-1 : 3
    Thread-0 : 2
    Thread-1 : 2
    Thread-0 : 1
    Thread-1 : 1
    Thread-0 : 0
    Thread-1 : 0
    

    在多线程环境下,调用同一对象的同步方法:

    public class SynchronizedDemo {
    
        public synchronized void synTest(){
            int i = 5;
            while (i-- > 0){
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            SynchronizedDemo demo1 = new SynchronizedDemo();
            SynchronizedDemo demo2 = new SynchronizedDemo();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.synTest();
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.synTest();
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-0 : 4
    Thread-0 : 3
    Thread-0 : 2
    Thread-0 : 1
    Thread-0 : 0
    Thread-1 : 4
    Thread-1 : 3
    Thread-1 : 2
    Thread-1 : 1
    Thread-1 : 0
    

    在多线程环境下,调用不同对象通过this修饰的局部代码块

    public class SynchronizedDemo {
    
        public void synTest(){
            synchronized (this){
                int i = 5;
                while (i-- > 0){
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        public static void main(String[] args) {
    
            SynchronizedDemo demo1 = new SynchronizedDemo();
            SynchronizedDemo demo2 = new SynchronizedDemo();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.synTest();
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo2.synTest();
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-0 : 4
    Thread-1 : 4
    Thread-0 : 3
    Thread-1 : 3
    Thread-0 : 2
    Thread-1 : 2
    Thread-0 : 1
    Thread-1 : 1
    Thread-0 : 0
    Thread-1 : 0
    

    对于this修饰的其实指的就是类的实例,所以它也属于对象锁,并不是类锁。


    在多线程环境下,调用不同对象通过其他实例类修饰的局部代码块

    public class SynchronizedDemo {
    
        public void synTest(){
            String str = new String("lock");
            synchronized (str){
                int i = 5;
                while (i-- > 0){
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        public static void main(String[] args) {
    
            SynchronizedDemo demo1 = new SynchronizedDemo();
            SynchronizedDemo demo2 = new SynchronizedDemo();
    
            Thread t1 = new Thread(() -> {
                demo1.synTest();
            });
    
            Thread t2 = new Thread(() -> {
                demo2.synTest();
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-0 : 4
    Thread-1 : 4
    Thread-1 : 3
    Thread-0 : 3
    Thread-1 : 2
    Thread-0 : 2
    Thread-1 : 1
    Thread-0 : 1
    Thread-1 : 0
    Thread-0 : 0
    

    我们可以看到,我们通过每次调用时实例一个String来进行同步代码块,但是并没有发生阻塞,因为每次生成的是一个实例String,锁的是String,每次都是不一样的,所以不会发生阻塞。


    可以通过上述的运行结果可以得到一下结论:

    在多线程环境下:

    • 调用不同对象的同步方法,不会发生阻塞
    • 调用相同对象的同步方法,会发生阻塞
    • 调用不同对象通过this修饰的局部代码块,不会发生阻塞
    • 调用不同对象通过其他实例类修饰的同步代码块,不会发生阻塞

    类锁

    在多线程环境下,多次调用类的静态同步方法:

    public class SynchronizedDemo {
    
        public static synchronized void synTest(){
            int i = 5;
            while (i-- > 0){
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    SynchronizedDemo.synTest();
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    SynchronizedDemo.synTest();
                }
            });
    
            t1.start();
            t2.start();
        }
    

    Output:

    Thread-0 : 4
    Thread-0 : 3
    Thread-0 : 2
    Thread-0 : 1
    Thread-0 : 0
    Thread-1 : 4
    Thread-1 : 3
    Thread-1 : 2
    Thread-1 : 1
    Thread-1 : 0
    

    在多线程环境下,多次调用被类锁的代码块:

    public class SynchronizedDemo {
        
        public void synTest(){
            synchronized (SynchronizedDemo.class){
                int i = 5;
                while (i-- > 0){
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        public static void main(String[] args) {
    
            SynchronizedDemo demo1 = new SynchronizedDemo();
            SynchronizedDemo demo2 = new SynchronizedDemo();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.synTest();
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo2.synTest();
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-1 : 4
    Thread-1 : 3
    Thread-1 : 2
    Thread-1 : 1
    Thread-1 : 0
    Thread-0 : 4
    Thread-0 : 3
    Thread-0 : 2
    Thread-0 : 1
    Thread-0 : 0
    

    对于对象SynchronizedDemo.class,实际上就是SynchronizedDemo这个类,也就是对类进行加锁。

    可以通过上述的运行结果可以得到一下结论:

    在多线程环境下:

    • 多次调用静态的同步方法,会进行阻塞
    • 不同对象调用被类锁的同步代码块,会进行阻塞

    类锁和对象锁同时存在

    在多线程环境下,同时调用同一对象的类锁和对象锁

    public class SynchronizedDemo {
    
        public static synchronized void synTestStatic() {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public synchronized void synTest() {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            SynchronizedDemo demo1 = new SynchronizedDemo();
    
            Thread t1 = new Thread(() -> {
                demo1.synTest();
            });
    
            Thread t2 = new Thread(() -> {
                SynchronizedDemo.synTestStatic();
            });
    
            t1.start();
            t2.start();
        }
    }
    

    Output:

    Thread-1 : 4
    Thread-0 : 4
    Thread-1 : 3
    Thread-0 : 3
    Thread-1 : 2
    Thread-0 : 2
    Thread-1 : 1
    Thread-0 : 1
    Thread-1 : 0
    Thread-0 : 0
    

    我们可以到看到,在多线程环境下,类锁和对象锁同时存在的情况下,多线程访问时不会阻塞,因为他们不是同一个锁。


    可以通过上述的运行结果可以得到一下结论:

    在多线程环境下:

    • 类锁和对象锁同时存在的情况下,不会发生阻塞

    总结

    image-20200425135801606

  • 相关阅读:
    2014 年最热门的国人开发开源软件TOP 100
    欢迎访问李培冠博客
    Go语言学习之路(持续更新)
    租房项目 获取地区信息服务
    租房项目 启动前的处理
    一步步带你用 FastDFS 搭建文件管理系统 详细的不得鸟
    golang 两个go程轮流打印一个切片
    golang 拷贝大切片一定比小切片代价大吗
    matlab 如何把数组A中与数组B中元素相同的元素删除
    golang 如何翻转含有中文 数字 英文字母等任意字符串
  • 原文地址:https://www.cnblogs.com/ArvinYL/p/12772905.html
Copyright © 2011-2022 走看看