JUC之通过案例深入理解锁的对象

通过不动代码下线程的执行先后,让我们来深入理解锁!

下面都是基于一个基本案例,对于类phone来说,有两个方法,一个打电话,一个发短信

  • 标准情况下,两个线程会按什么顺序执行呢?为了排除随机性,让call方法延迟2秒
import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(() -> {
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            phone.Text();
        }).start();
    }
}

class Phone {
    public synchronized void call() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        System.out.println("打电话");
    }

    public synchronized void Text() {
        System.out.println("发短信");
    }
}

输出结果是等待两秒,输出 打电话 然后输出 发短信

原因是 synchronized 锁的对象是方法的调用者,即两个方法用的是同一个锁,所以谁先拿到,谁就先执行

  • 增加了一个普通方法输出Hello,会先输出谁呢?
import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(() -> {
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            phone.Text();
        }).start();

        phone.hello();
    }
}

class Phone {
    public synchronized void call() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        System.out.println("打电话");
    }

    public synchronized void Text() {
        System.out.println("发短信");
    }

    public void hello(){
        System.out.println("hello!");
    }
}

结果是直接输出hello!然后分别是打电话和发短信

原因是hello不是同步方法没有被加锁,所以不受影响

  • 如果两个方法分别对应两个对象先输出谁呢?
import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            try {
                phone1.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            phone2.Text();
        }).start();

    }
}

class Phone {
    public synchronized void call() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        System.out.println("打电话");
    }

    public synchronized void Text() {
        System.out.println("发短信");
    }
}

输出结果是 发短信 然后输出 打电话

由于有两个对象,于是有了两个调用者,也就是有了两把锁,互相不会影响

  • 如果两个同步方法是静态的,一个对象,先输出谁呢?

这个会和标准状态的顺序一样,不做讨论,重点是下面的

  • 如果两个同步方法是静态的,两个个对象,先输出谁呢?
import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            try {
                phone1.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            phone2.Text();
        }).start();

    }
}

class Phone {
    public static synchronized void call() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        System.out.println("打电话");
    }

    public static synchronized void Text() {
        System.out.println("发短信");
    }
}

结果是等待两秒,输出 打电话 然后输出 发短信

这是因为synchronized 锁的对象是方法的调用者,而静态方法在类一加载的时候就有了,因此synchronized锁的是Class对象,即类模板,而类模板在运行过程中是唯一的,不论是phone1还是phone2都是用的同一个类模板,因此先使用类模板的call方法会先执行

  • 如果有一个是静态方法,另一个不是,一个对象或者两个对象的情况下,谁先输出呢?
    结果都是先输出 发短信,再输出 打电话

这是因为对于静态方法synchronized 锁的是类模板,对于非静态方法,锁得是当前的调用者,所以两者不会互相干扰,因此延迟的打电话会后输出

总结

  • 对于非静态的方法,synchronized锁得是this,即当前对象,具体的某一个手机
  • 对于静态的方法,synchronized锁得是Class,即唯一的一个类模板,不同的同一个类模板创建的对象,只要使用这一个静态方法时,都会上锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值