8锁现象

如何判断锁的是什么?

首先我们先来看下面的代码。思考下面两个问题。

/**
 * 1.Q:下面程序执行后,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影”
 * 2.Q:若watchMovie方法延迟4秒,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影” */
public class Test01 {
    public static void main(String[] args){
        TV tv = new TV();
        new Thread(()->{
            tv.watchMovie();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            tv.playGame();
        },"B").start();
    }
}

class TV{

    public synchronized void watchMovie(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("看电影");
    }

    public synchronized void playGame(){
        System.out.println("打游戏");
    }
}

synchronized 锁的对象是方法的调用者!
就上面代码而言,看电影和玩游戏两个方法是用的TV对象的一把锁,所以谁先拿到谁先执行!

我们在思考下面两个问题。

/**
 * 3.Q:增加了一个普通方法后,是先打印 “开机” 还是 “看电影” 呢? A:先打印“开机”
 * 4.Q:若两个对象,两个同步方法,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏” */
public class Test02 {
    public static void main(String[] args){
        TV2 tv1 = new TV2();
        TV2 tv2= new TV2();
        new Thread(()->{
            tv1.watchMovie();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            tv2.playGame();
        },"B").start();
    }
}

class TV2{

    public synchronized void watchMovie(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("看电影");
    }

    public synchronized void playGame(){
        System.out.println("打游戏");
    }

    public void open(){
        System.out.println("开机");
    }
}

就问题3而言,我们之前了解过synchronized 锁的对象是方法的调用者!而普通方法没有synchronized修饰,不受锁控制,所以先执行。
就问题4而言,两个对象,就是两个调用者,也就意味着有两把锁,所以要受时间延迟影响,先打印“打游戏”!

好的,那我们再看下面两组问题:

/**
 * 5.Q:增加两个静态方法,只有一个对象,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影”
 * 6.Q:若两个对象,两个静态方法,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影” */
public class Test03 {
    public static void main(String[] args){
        TV3 tv1 = new TV3();
        TV3 tv2 = new TV3();
        new Thread(()->{
            tv1.watchMovie();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            tv2.playGame();
        },"B").start();
    }
}

class TV3{

    public static synchronized void watchMovie(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("看电影");
    }

    public static synchronized void playGame(){
        System.out.println("打游戏");
    }
}

static 静态,全局唯一,static 方法在类加载的时候就存在了,synchronized 锁static 方法本质是锁TV对象的Class模板,类的Class模板只有一个,换而言之,调用者只有一个,锁只有一把,所以还是谁先拿到谁先执行!

最后再来看下面两个问题:

/**
 * 7.Q:增加1个静态 synchronized 方法,1个普通 synchronized 方法,只有一个对象,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏”
 * 8.Q:增加1个静态 synchronized 方法,1个普通 synchronized 方法,两个对象,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏” */
public class Test04 {
    public static void main(String[] args){
        TV4 tv1 = new TV4();
        TV4 tv2 = new TV4();

        new Thread(()->{
            tv1.watchMovie();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            tv2.playGame();
        },"B").start();
    }
}

class TV4{

    public static synchronized void watchMovie(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("看电影");
    }

    public synchronized void playGame(){
        System.out.println("打游戏");
    }
}

就问题7而言,静态synchronized方法和普通synchronized锁的调用者不是一个,前者是类的Class模板,后者是对象,所以有两个调用者,也就存在两把锁,因此,时间延迟的原因占主导。同理问题8也是如此,两个调用者两把锁!

总结:关键理解锁的对象是方法的调用者!锁的对象无外乎两种,一种是new的对象,而一种就是Class模板。要分清具体情况下究竟锁的是什么?

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容