前言
synchronized是Java中解决并发问题的一种常用方法,它主要的作用如下
- 确保线程互斥的访问代码
- 保证变量的可见性
- 解决重排序
基本使用
synchronized可以修饰方法、代码块,下面看一个简单的例子
public class SynTest {
public void lockTest() {
synchronized (this) {
System.out.println(233);
}
}
}
对这段代码使用javap -c SysTest.class进行反编译
Compiled from "SynTest.java"
public class com.happycode.lock.SynTest {
public com.happycode.lock.SynTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void lockTest();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: sipush 233
10: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
13: aload_1
14: monitorexit
15: goto 23
18: astore_2
19: aload_1
20: monitorexit
21: aload_2
22: athrow
23: return
Exception table:
from to target type
4 15 18 any
18 21 18 any
}
我们需要关注的是monitorenter和monitorexit指令,这些是jvm提供的,每个对象有一个监视器锁(Monitor),当 Monitor 被占用时就会处于锁定状态。monitorenter指令回去尝试获取Monitor,如果Monitor的计数器为0,则获取成功,线程进入,Monitor计数器加1,如果不为0,线程就会阻塞。也能看出synchronized是非公平的。其实wait和notify也依赖监视器Monitor。这就是为什么他们只能在synchronized块里。