自旋和自适应自旋
自旋等待其他占用锁的线程释放.
自适应的自旋,由前一次在同一个锁上的自旋时间和锁的拥有者状态来判断.是否进行自旋,以及自旋的次数
锁消除
在JIT中,如果检测到不可能存在数据竞争,则会直接消除锁,例如在一个方法内部定义StringBuffer并操作,会被替换为StringBuilder.
锁粗化
在一系列的连续操作中都对同一个对象反复加锁和解锁,会把锁同步的范围扩展.以避免频繁的加解锁导致的性能消耗
轻量级锁
并非用于替代重量级锁.
要了解对象头分布
过程
- 在当前线程的栈帧中建立一个名为锁记录的空间(LR)
- 将Mark Word拷贝到其中,命名为Displaced Mark Word
- cas将mark word更新为 lr 的指针.如果成功了则说明进入了轻量级锁定
- 如果存在两条以上的线程争抢,会膨胀为重量级锁
- 在轻量级锁中,如果获取对象的hashCode,也会膨胀为重量级锁(Object的hashcode)
- 解锁时使用cas将mark word复原
依据
对于绝大部分的锁,在整个同步周期内都是不存在竞争的.
如果确实存在锁竞争,除了互斥量本身的开销外,还额外发生了cas操作的开销,因此反而会比传统的重量级锁更慢
偏向锁
锁会偏向于第一个获取的线程,如果一直没有被其他线程获取,则永远不需要再同步.
一旦出现另外一个线程去获取锁,则偏向模式马上结束.根据锁目前是否被锁定决定是否撤销偏向
当一个对象被计算过一致性hash后就再也不能进入偏向锁的状态了,并且如果正处于偏向状态,则会立即膨胀为重量锁
实验部分
https://github.com/lT1161558158/sync_testing