锁的撤销
Java对象头


调用对象的hashCode
- 重量级锁会在monitor中记录hashcode
- 轻量级锁会在锁记录中记录hashcode
调用了对象的hashcode,但偏向锁的对象markword中存储的是线程id,如果调用hashcode会导致偏向锁被撤销
其他线程使用对象
当一个线程使用完偏向锁对象后,另一个线程使用偏向锁对象,会将偏向锁升级为轻量级锁。(错开使用)
| 使用前 | 使用时 | 使用后 |
|---|---|---|
| 偏向锁t1 | 轻量级锁 | 无偏向 |
调用wait/notify
批量重偏向
原理:以class为单位,为每个class维护一个偏向锁撤销计数器,每一次该class的对象发生偏向撤销操作时,该计数器+1,当这个值达到重偏向阈值(默认20)时,JVM就认为该class的偏向锁有问题,因此会进行批量重偏向。
如果锁对象被多个线程访问,但没有竞争。这种情况下偏向线程t1的锁对象仍有可能重新偏向线程t2,重偏向会重置锁对象的线程ID。
当撤销偏向锁的次数达到阈值20次后,JVM会觉得偏向的线程可能有误,于是会在其他线程加锁时重新偏向加锁的线程。
| 使用前 | 使用时 | 使用后 | 第20次 |
|---|---|---|---|
| 偏向锁t1 | 轻量级锁 | 无偏向 | 偏向锁t2 |
批量撤销
当达到重偏向阈值后,假设该class计数器继续增长,当其达到批量撤销的阈值后(默认40),JVM就认为该class的使用场景存在多线程竞争,会标记该class为不可偏向,之后,对于该class的锁,直接走轻量级锁的逻辑。
- t1线程把39个dog对象作为锁对象,加上偏向锁。
- t2线程把这39个dog对象作为锁对象。前19个dog的偏向锁撤销,变为无偏向的普通状态。从第20个dog开始,批量重偏向t2线程。
- t3线程把这39个dog对象作为锁对象。前19个dog是无偏向的锁。从第20个dog开始,由于dog现在是偏向t2线程的偏向锁,t3使用dog作为锁对象后,会把dog的偏向锁撤销。
- 1~19由偏向锁t1 -> 无偏向的普通状态,使得20~39偏向t2 ------------------------撤销了19次
- 20~39由偏向锁t1 -> 偏向锁t2(批量重偏向) -> 无偏向的普通状态---------------撤销了20次
在以上过程中,这39个dog对象共撤销了偏向锁39次。在下一次创建Dog类的对象时,默认创建无偏向的锁。
浙公网安备 33010602011771号