美文网首页
线程八锁案例分析

线程八锁案例分析

作者: xhlc02 | 来源:发表于2020-04-15 11:31 被阅读0次

    1.两个线程调用同一个对象的两个同步方法

    public class ThreadDemo {
    
       public static void main(String[] args) {
           Phone phone = new Phone();
           new Thread(()->{
               phone.sendSms();
           },"A").start();
           new Thread(()->{
               phone.call();
           },"B").start();
       }
    
    }
    class Phone{
       /**
        * synchronized 锁的对象是方法的调用者!、
        * 两个方法用的是同一个锁,谁先拿到谁执行!
        */
       public synchronized void sendSms(){
           System.out.println("发短信");
       }
       public synchronized void call(){
           System.out.println("打电话");
       }
    }
    

    运行的结果如下

    发短信
    打电话

    结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行。

    2.新增Thread.sleep()给某个方法

    public class ThreadDemo {
    
       public static void main(String[] args) {
           Phone phone = new Phone();
           new Thread(()->{
               phone.sendSms();
           },"A").start();
           new Thread(()->{
               phone.call();
           },"B").start();
       }
    }
    class Phone{
       /**
        * synchronized 锁的对象是方法的调用者!、
        * 两个方法用的是同一个锁,谁先拿到谁执行!
        */
       public synchronized void sendSms(){
           try {
               //睡眠4秒钟
               TimeUnit.SECONDS.sleep(4);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("发短信");
       }
    
       public synchronized void call(){
           System.out.println("打电话");
       }
    }
    

    // 等待4秒。
    发短信
    打电话

    结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。

    3.新增一个线程调用新增的一个普通方法

    public class ThreadDemo {
    
       public static void main(String[] args) {
           Phone phone = new Phone();
           new Thread(()->{
               phone.sendSms();
           },"A").start();
           new Thread(()->{
               phone.call();
           },"B").start();
           new Thread(()->{
               phone.hello();
           },"C").start();
       }
    }
    class Phone{
       /**
        * synchronized 锁的对象是方法的调用者!、
        * 两个方法用的是同一个锁,谁先拿到谁执行!
        */
       public synchronized void sendSms(){
           try {
               //睡眠4秒钟
               TimeUnit.SECONDS.sleep(4);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("发短信");
       }
    
       public synchronized void call(){
           System.out.println("打电话");
       }
    
       /**
        *  这里没有锁!不是同步方法,不受锁的影响
        */
       public void hello(){
           System.out.println("hello");
       }
    }
    
    

    运行结果:

    hello
    //等待4秒
    发短信
    打电话

    结果分析:新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。

    4.两个线程调用两个对象的同步方法,并且睡眠其中一个

    public class ThreadDemo {
    
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 =new Phone();
            new Thread(()->{
                phone1.sendSms();
            },"A").start();
            new Thread(()->{
                phone2.call();
            },"B").start();
    
        }
    }
    class Phone{
        /**
         * synchronized 锁的对象是方法的调用者!、
         * 两个方法用的是同一个锁,谁先拿到谁执行!
         */
        public synchronized void sendSms(){
            try {
                //睡眠4秒钟
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发短信");
        }
    
        public synchronized void call(){
            System.out.println("打电话");
        }
    
        /**
         *  这里没有锁!不是同步方法,不受锁的影响
         */
        public void hello(){
            System.out.println("hello");
        }
    }
    

    运行结果

    打电话
    //等待4秒
    发短信

    结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

    5.增加两个静态的同步代码,同一个对象去调用不同的代码块

    public class ThreadDemo {
    
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 =new Phone();
            new Thread(()->{
                phone1.sendSms();
            },"A").start();
            new Thread(()->{
                phone1.call();
            },"B").start();
    
        }
    }
    class Phone{
        /**
         * synchronized 锁的对象是方法的调用者!、
         * 两个方法用的是同一个锁,谁先拿到谁执行!
         * static 类一加载就有了!锁的是Class
         */
        public static synchronized void sendSms(){
            try {
                //睡眠4秒钟
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发短信");
        }
    
        public static synchronized void call(){
            System.out.println("打电话");
        }
    
    
    }
    
    

    //等待4秒
    发短信
    打电话

    结论:被synchronized和static修饰的方法,锁的对象是类的class对象,因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法

    6.两个对象调用两个静态的同步方法

    public class ThreadDemo {
    
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 =new Phone();
            new Thread(()->{
                phone1.sendSms();
            },"A").start();
            new Thread(()->{
                phone2.call();
            },"B").start();
    
        }
    }
    class Phone{
        /**
         * synchronized 锁的对象是方法的调用者!、
         * 两个方法用的是同一个锁,谁先拿到谁执行!
         * static 类一加载就有了!锁的是Class
         */
        public static synchronized void sendSms(){
            try {
                //睡眠4秒钟
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发短信");
        }
    
        public static synchronized void call(){
            System.out.println("打电话");
        }
    }
    

    //等待4秒
    发短信
    打电话

    结论:被synchronized和static修饰的方法,锁的对象是类的class对象,因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法

    7.1个静态的同步方法,1个普通的同步方法 ,使用一个对象调用

    public class ThreadDemo {
    
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 =new Phone();
            new Thread(()->{
                phone1.sendSms();
            },"A").start();
            new Thread(()->{
                phone1.call();
            },"B").start();
    
        }
    }
    class Phone{
        /**
         * synchronized 锁的对象是方法的调用者!、
         * 两个方法用的是同一个锁,谁先拿到谁执行!
         * static 类一加载就有了!锁的是Class
         */
        public static synchronized void sendSms(){
            try {
                //睡眠4秒钟
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发短信");
        }
        /**
         * 普通的同步方法  锁的调用者
         */
        public  synchronized void call(){
            System.out.println("打电话");
        }
    }
    

    打电话
    //等待4秒
    发短信

    结论:被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

    8.1个静态的同步方法,1个普通的同步方法 ,使用两个对象调用

    public class ThreadDemo {
    
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 =new Phone();
            new Thread(()->{
                phone1.sendSms();
            },"A").start();
            new Thread(()->{
                phone2.call();
            },"B").start();
    
        }
    }
    class Phone{
        /**
         * synchronized 锁的对象是方法的调用者!、
         * 两个方法用的是同一个锁,谁先拿到谁执行!
         * static 类一加载就有了!锁的是Class
         */
        public static synchronized void sendSms(){
            try {
                //睡眠4秒钟
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发短信");
        }
        /**
         * 普通的同步方法  锁的调用者
         */
        public  synchronized void call(){
            System.out.println("打电话");
        }
    }
    

    打电话
    //等待4秒
    发短信

    结论:被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

    总结:
    1.一个类有多个synchronized 方法,被同一个对象调用时候,后来者必须进行等待,等待先来者释放才可以进行访问。
    2.普通方法与同步方法无关
    3.加入static修饰的方法,锁的是类
    4.不同对象或者同一对象调用同一类中的不同静态同步代码块,后来者必须进行等待,等待先来者释放才可以进行访问。

    相关文章

      网友评论

          本文标题:线程八锁案例分析

          本文链接:https://www.haomeiwen.com/subject/rkpqvhtx.html