在终端执行以下命令查看class文件的字节码
Amy:~ Amy$ cd /Users/Amy/Documents/workplace/project/bin/com/roocon/thread/t3
Amy:t3 Amy$ javap -verbose Sequence.class
这里用一个片段讲解:
public int getSubOrAdd();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #18 // Field value:I
7: ifle 21
10: getstatic #18 // Field value:I
13: iconst_1
14: isub
15: putstatic #18 // Field value:I
18: goto 29
21: getstatic #18 // Field value:I
24: iconst_1
25: iadd
26: putstatic #18 // Field value:I
29: aload_1
30: monitorexit
31: goto 37
34: aload_1
35: monitorexit
36: athrow
Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。
1、monitorenter:
每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
- 1.如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
- 2.如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
- 3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
2、monitorexit:
执行monitorexit的线程必须是object所对应的monitor的所有者。
- 指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。