一、monitor管程工作原理:
首先,synchronized是一个对象锁,当线程运行到某个临界区,这个临界区使用synchronized对对象obj进行了上锁,此时底层发生了什么?
1.当synchronized对obj上锁后,synchronized会与操作系统层面的monitor管程建立连接,也就是在obj的header中构建一个指向monitor的指针。
2.此时线程访问临界区代码,发现Obj锁,所以去查看obj的header中的mark word中指向管程monitor的指针,从而找到monitor。线程会去查看monitor中的owner部分,访问owner,如果owner目前没有线程访问,该线程成为owner去执行临界区代码段。如果存在owner,线程就被放进monitor中的entryset中,相当于等待队列,等待执行完临界区代码段的线程的唤醒。
二、其中线程与obj的交互如下:
线程访问临界区后,会在栈帧中创建obj的指针以及lock record。
lockrecord中记录着 当前锁记录的地址。
然后会与obj进行交互,尝试使用cas将 lock record中的地址+锁状态 与 obj中的mark word交换。
如果交换成功,mark word 中存储的lock状态就会从00转换为01,表示当前的obj为轻量级锁。
现在的lock record中存放着obj 的 地址, 而 obj中也有到线程锁记录的地址。
完整流程:
首先需要明确,轻量级锁不需要访问monitor,因为与操作系统层面的monitor管程建立连接的花销很高。
在线程之间没有因为临界区而交互时,此时挂载的是轻量级锁。流程如下:
首先线程调用任何方法都会将该方法存放在方法区中,并且在线程的栈帧中保存该方法的局部变量、方法参数以及返回地址。
由于该方法有临界区(加锁),此时在线程的栈帧中还会维护锁对象(synchronized是一个对象锁,锁住的对象需要创建对应的索引信息)的地址以及lock record(锁记录)用于存储当前线程的地址。
同时会在栈帧中的额外槽位slot中维护锁对象的header中的mark word(用于释放锁的还原)。
执行CAS 操作:构造一个新的 Mark Word:
-
低两位改为
01
(轻量级锁标志) -
高位填入指向自己栈帧 Lock Record 的地址
然后对对象头做原子 CAS: -
成功 → 轻量级锁加锁成功,对象头和 Lock Record 双向链上了;
-
失败 → 表示有另一个线程同时在抢这个锁,进入自旋重试或锁膨胀(升级到重量级锁)。
解锁的过程只需要再将栈帧中维护的旧对象头替换回对象中即可。
当有其他线程发现锁对象的锁状态不为00,此时就会进行后续处理,比如自旋,自旋失败后,将后续的锁升级为重量级锁。