偏向锁、轻量级锁、重量级锁的升级以及区别

锁的状态:

  • 无锁状态
  • 偏向锁状态
  • 轻量级锁状态
  • 重量级锁状态

四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级。

要注意的是,这四种状态都不是Java语言中的锁,而是Jvm为了提高锁的获取与释放效率而做的优化(使用synchronized时)。

首先通过一个小例子来解释一下三种锁的区别:

假如家里只有一个碗,当我自己在家时,没有人会和我争碗,这时即为偏向锁状态

当我和女朋友都在家吃饭时,如果女朋友不是很饿,则她会等我吃完再用我的碗去吃饭,这就是轻量级锁状态

当我和女朋友都很饿的时候,这时候就会去争抢这唯一的一个碗(贫穷的我)吃饭,这就是重量级锁状态

偏向锁

偏向锁的由来:

大多数情况下,锁不存在多线程竞争,而是总是由同一线程多次获得时,为了使线程获得锁的代价更低而引入了偏向锁。

偏向锁的使用:

当线程进入和退出同步块时,需要经历几个测试步骤:

  1. 测试对象头Mark Word(默认存储对象的HashCode,分代年龄,锁标记位)里是否存储着指向当前线程的偏向锁。
  2. 若测试失败,则测试Mark Word中偏向锁标识是否设置成1(表示当前为偏向锁)
  3. 没有设置则使用CAS竞争,否则尝试使用CAS将对象头的偏向锁指向当前线程

偏向锁的撤销:

当其他线程尝试竞争偏向锁时,就会释放锁,锁的撤销,需要等待全局安全点,分为以下几个步骤:

  1. 暂停拥有偏向锁的线程,检查线程是否存活
  2. 处于非活动状态,则设置为无锁状态
  3. 存活,则重新偏向于其他线程或者恢复到无锁状态或者标记对象不适合作为偏向锁
  4. 唤醒线程

偏向锁的升级:

当有第二个线程进入同步代码块时,则升级为轻量级锁

轻量级锁

轻量级锁的加锁:

如果成功使用CAS将对象头重的Mark Word替换为指向锁记录的指针,则获得锁,失败则当前线程尝试使用自旋(循环等待)来获取锁。

轻量级锁的解锁:

当有另一个线程与该线程同时竞争时,锁会升级为重量级锁。为了防止继续自旋,一旦升级,将无法降级。

重量级锁

重量级锁特点:

其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程,进行竞争。

三种锁的对比

但是也有其他的观点是锁可以降级的,就是在当 JVM 进入安全点(SafePoint)的时候,会检查是否有闲置的 Monitor,然后试图进行降级。目前还不能确定这种观点的正确性,如果有大佬知道,可以指教。

原文地址:https://www.jianshu.com/p/9998a9db17f7

https://blog.csdn.net/zhangguozhangyue/article/details/82624707

猜你喜欢

转载自blog.csdn.net/hy_coming/article/details/88824631