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

锁的状态:

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

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

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

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

偏向锁

偏向锁、轻量级锁、重量级锁的升级以及区别_第1张图片

一个线程操资源,此时没有其他线程会竞争,这是偏向锁,大多数情况下,锁不存在多线程竞争,而是总是由同一线程多次获得时,为了使线程获得锁的代价更低而引入了偏向锁

 

偏向锁、轻量级锁、重量级锁的升级以及区别_第2张图片

 

轻量级锁

两个个线程操资源,其中一个线程需要等待另外一个线程操作完释放锁才能进入,这是偏向锁

 

 

偏向锁、轻量级锁、重量级锁的升级以及区别_第3张图片

 

偏向锁、轻量级锁、重量级锁的升级以及区别_第4张图片

偏向锁的由来:

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

偏向锁的使用:

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

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

偏向锁的撤销:

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

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

偏向锁的升级:

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

轻量级锁

轻量级锁的加锁:

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

轻量级锁的解锁:

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

重量级锁

重量级锁特点:

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

三种锁的对比

 

偏向锁、轻量级锁、重量级锁的升级以及区别_第5张图片

 

 

锁之间的转化

偏向锁、轻量级锁、重量级锁的升级以及区别_第6张图片

 

偏向锁、轻量级锁、重量级锁的升级以及区别_第7张图片

你可能感兴趣的:(并发编程)