我们都知道,不论是在学习、面试和工作中,多线程一直都被视为很重要的一项技术,也是开发人员交流中老生常谈的话题。
相信正在阅读的你,脑海中已经浮现出了多线程的知识。许多小伙伴对于多线程都有这样的困扰:知识一看就会,遇到场景就废。屏幕前的你是否也有这样的困扰呢?
就比如我们都知道synchronized实现同步具体表现为以下三种形式:
- 对于普通同步方法,锁是当前实例对象
- 对于静态同步方法,锁是当前类的Class对象
- 对于同步方法块,锁是synchronized括号里配置的对象
但是一到真实场景中,就难以判断synchronized锁的是谁了。
那么本篇文章,引用了著名的”8锁现象“,每个问题都会附一套代码,来帮助你彻底理解synchronized到底锁了什么,让你不论在多么复杂的场景下,都可以正确地判断锁的是谁。
想深入了解synchronized锁的读者
可以阅读笔者的上一篇作品:synchronized的实现原理与应用&Java对象的内存布局
八锁现象
8锁,就是关于锁的八个问题!
读者可以检验一下自己是否能将这八个问题都答对呢?
问题1
运行下面的代码,两个线程执行,是先打印发消息还是打电话呢?
public class Demo1 {
public static void main(String[] args) {
WeChat weChat = new WeChat();
new Thread(()->{
weChat.sendMessage();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
weChat.call();
},"B").start();
}
}
class WeChat{
public synchronized void sendMessage(){
System.out.println("send message");
}
public synchronized void call(){
System.out.println("call");
}
}
答: 先发消息,1秒后打电话
解析:
在这种情况下,synchronized锁的是当前的实例对象,两个方法用的是同一个锁(都是同一个weChat对象),因为线程A先拿到了锁,所以线程A先执行,即先发消息
问题2
在sendMessage方法中添加5秒的延时,运行结果又是怎样的呢?
代码(仅修改了WeChat类的sendMessage方法):
public class Demo2 {
public static void main(String[] args) {
WeChat weChat = new WeChat();
new Thread(()->{
weChat.sendMessage();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
weChat.call();
},"B").start();
}
}
class WeChat{
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(5);
} catch <