◆synchronized: 依赖JVM
◆Lock: 依赖特殊的CPU指令, 由代码实现, ReentrantLock
◆以下内容主要讨论重量级锁(标志10)的原理. 偏向锁, 轻量级锁相关有空再发.
synchronized的字节码
pubLic class Decompilation14 {
private Object object = new 0bject() ;
public void insert(Thread thread) {
synchronized (object) {
}
}
}
public void insert();
Code:
stack=2,locals=4, args_size=2
0: aload_0
1: getfield #3 // Field object:Ljava/lang/0bject;
4: dup
5: astore_2
6: monitorenter // 获取锁
7: aload_2
8: monitorexit // 释放锁,正常退出的时候
9: goto 17
12: astore_3
13: aload_2
14: monitorexit // 释放锁,抛出异常的时候
15: aload_3
16: athrow
17: return
monitorenter指令
每个对象有一个监视器锁(monitor), 当monitor被占用时就会处于锁定状态。
monitorenter指令会尝试获取monitor的持有权,即尝试获取锁. 一个时间只能被一个线程获得所有权.
monitorenter会将锁对象的计数器+1,重入锁时也会+1,计数器就会变成2,3,4...
monitorenter的+1操作最终是由CPU的完成的, 可以保证多个线程的互斥性
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
monitorexit指令
执行monitorexit的线程必须是objectref所对应的monitor的所有者。
monitorexit会将锁对象的计数器-1, 为0时释放锁, 且唤醒所有该锁等待线程开始抢锁