zoukankan      html  css  js  c++  java
  • 八锁问题

    场景一

    import java.util.concurrent.TimeUnit;
    
    /*
    * 场景一:sendMsg和call都是同步方法,先打印谁?
    * 答案:A-->发短信
    * 分析:被synchronized修饰属于同步方法,这里争夺地是同一把锁,谁先调用锁就先执行
    * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            //Phone phone2 = new Phone();
            new Thread(()->{phone1.sendMsg();},"A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(()->{phone1.call();},"B").start();
        }
    }
    class Phone{
        public synchronized void sendMsg(){
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public synchronized void call(){
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景二

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景二:sendMsg和call都是同步方法,不过被先调用的sendMsg方法块内增加了休眠,先打印谁?
     * 答案:A-->发短信
     * 分析:线程A和线程B争夺地是同一把锁,谁先调用就先执行
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            //Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone1.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public synchronized void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景三

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景三:call方法改为普通方法,sendMsg改为同步方法,先打印谁?
     * 答案:B-->打电话
     * 分析:线程A在争夺抢锁,线程B和锁无关,虽然线程A被先调用执行,但sendMsg内的休眠使它比call晚了1s
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            //Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone1.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景四

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景四:新建另一个对象phone2,两个线程分别使用两个对象调用方法,先打印谁?
     * 答案:B-->打电话
     * 分析:synchronized锁的是调用的对象,这里有两把锁,线程B不必等待线程A释放锁即可执行call方法
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone2.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public synchronized void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景五

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景五:两个方法前面用static synchronized修饰,先打印谁?
     * 答案:A-->发短信
     * 分析:static synchronized锁的是调用的类,所以这里还是同一把锁,线程B必须等待线程A释放锁才能执行call方法
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            //Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone1.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public static synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public static synchronized void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景六

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景六:一个方法前面用static synchronized修饰,另一个前面用synchronized修饰,先打印谁?
     * 答案:B-->打电话
     * 分析:sendMsg方法锁的是类,call方法锁的是对象,这里有两把锁
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            //Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone1.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public static synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public static void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景七

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景七:两个方法前面都用static synchronized修饰,同时新建另外一个对象phone2,先打印谁?
     * 答案:A-->发短信
     * 分析:这里锁的是类,所以两个对象争夺地还是同一把锁
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone2.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public static synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public static synchronized void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    场景八

    import java.util.concurrent.TimeUnit;
    
    /*
     * 场景八:一个方法前面用static synchronized修饰,另一个前面用synchronized修饰,两个对象分别调用不同方法,先打印谁?
     * 答案:B-->打电话
     * 分析:用static synchronized修饰锁的是类,用用synchronized修饰锁的是对象,所以两个对象争夺地是不同的两把锁
     * */
    public class Lock8 {
        public static void main(String[] args) {
            Phone phone1 = new Phone();
            Phone phone2 = new Phone();
            new Thread(() -> {
                phone1.sendMsg();
            }, "A").start();
            //保证线程A先到达Runnable状态,线程B后到达Runnable状态
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                phone2.call();
            }, "B").start();
        }
    }
    
    class Phone {
        public static synchronized void sendMsg() {
            //当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
            //这里必须保证该休眠与Main方法内的休眠存在差值
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->发短信");
        }
    
        public synchronized void call() {
            System.out.println(Thread.currentThread().getName() + "-->打电话");
        }
    }
    

    总结

    1. 对于八锁问题,首先明白Main方法内休眠和先调用方法内休眠的不同作用,这是前提条件;
    2. synchronized修饰锁的是调用的对象,被static synchronized修饰锁的是调用的类;
    3. 不管两个线程执行地是不是一个对象的方法,只要争夺地是同一把锁就按线程顺序执行。
  • 相关阅读:
    自定义弹框
    微信分享
    RichText
    UIDatePicker
    微服务概述
    超详细十大经典排序算法总结
    《Java程序员面试笔试宝典》学习笔记(持续更新……)
    知识图谱让分析工作化繁就简
    构建以知识图谱为核心的下一代数据中台
    智慧安监系统为城市安全监管提供保障
  • 原文地址:https://www.cnblogs.com/i-chase/p/14215296.html
Copyright © 2011-2022 走看看