锁的撤销

Java对象头

image

image

调用对象的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的锁,直接走轻量级锁的逻辑。

  1. t1线程把39个dog对象作为锁对象,加上偏向锁。
  2. t2线程把这39个dog对象作为锁对象。前19个dog的偏向锁撤销,变为无偏向的普通状态。从第20个dog开始,批量重偏向t2线程。
  3. 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类的对象时,默认创建无偏向的锁。
posted @ 2024-01-19 11:48  ︶ㄣ演戲ㄣ  阅读(23)  评论(0)    收藏  举报