如果你不想平庸,就请勿停止前进的脚步。同样作为主流的开发语言,Java也没有停止前进,而是一直在优化进步。更多内容请搜索关注微信公众号:Different Java

摘要

  1. 为什么需要锁优化
  2. 锁的状态
  3. 偏向锁
  4. 轻量级锁
  5. 锁升级
  6. 锁消除

1. 为什么需要锁优化

synchronized Lock在JDK1.6之前效率低下,原因我们已经在悲观锁中讲述过了,因此为了提高锁的效率,JVM对其进行了优化。

2. 锁的状态

锁优化的过程也是锁状态变更的过程,锁的状态目前有以下几种:

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

锁的状态是如何标记的,这就需要借助Java对象在内存中的存储格式。Java对象在虚拟机中大致分为三部分:

  • 对象头
  • 实例数据
  • 对齐填充

对象头中存储对象自身运行时的数据(Mark Word)以及类型指针,而锁的状态则保存在Mark Word中。 由于锁状态的不同,Mark Word也会不相同。各种锁状态下的Mark Word(32位 JVM)如下:

WX20210509-185643@2x.png

3. 偏向锁

如果一个线程获得了锁,那么锁就进入偏向模式,此时对象的Mark Word也会进入偏向锁模式,当该线程再次请求锁无需执行获取锁操作,省去了大量获取锁的时间。对于竞争不激烈的场合偏向锁的提升效果还是很明显的,但是竞争激烈的场合建议关闭偏向锁,可以使用-XX:-UseBiasedLocking此参数关闭偏向锁。

偏向锁的锁定和撤销的简要步骤如下:

WX20210509-213842@2x.png

4. 轻量级锁

当偏向锁失败时,虚拟机不会立即挂起线程。它会将对象头部作为指针,指向持有锁的线程堆栈内部,来判断一个线程是否持有对象锁。如果成功,则可以进入临界区,失败以后会膨胀为重量级锁,但是膨胀后,虚拟机还会做最后一次努力优化,那就是自旋锁。

轻量级锁膨胀重量级锁的简要步骤如下:

WX20210509-223750@2x.png

5. 自旋锁

由于当前线程暂时无法获得锁,但何时获取也是未知的。有可能在几个CPU时钟周期后便可得到锁,此时虚拟机或进行一次赌注,会让当前线程做几个空循环,在经过若干次循环后如果可以得到锁便进入临界区,如果不能获得锁,则将线程真正从操作系统层面挂起。

6. 锁升级

WX20210509-225054@2x.png

锁只能升级不能降级,锁升级的详细步骤如下:

WX20210509-225239@2x.png

7. 锁消除

锁消除是JVM运行时通过JIT编译来发现不可能存在共享资源竞争的锁,然后将其消除(消除的关键是要借助逃逸分析),节省无意义的请求时间。

本期的Java锁优化就介绍到这,我是shysh95,我们下期再见!


shysh
82 声望17 粉丝

« 上一篇
AQS
下一篇 »
Future Java