偷偷告诉你,synchronized不再使用偏向锁啦

Synchronized 底层优化是Java面试常考察的点。简略来说,Synchronzied 采用逐步升级的加锁机制来降低加锁成本,每次加锁失败就升级竞争下一级锁,每升高一级,加锁成本就会提高。

在 Java 中,加锁就是线程 用锁对象记录自己的一个标记 。当其他线程加锁扫描到锁对象已被其他线程标记,就会加锁失败。不再执行后续临界区的代码。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 一、 S y n c h r o n i z e d 锁升级过程 \color{blue}{一、Synchronized 锁升级过程} </math>一、Synchronized锁升级过程

Synchronized 首先尝试获取偏向锁(Biased lock),偏向锁会把对象头中的线程编号字段指向自己,表示锁对象被该线程标记。如果指向失败,则撤销偏向锁,升级为轻量级锁(Lightweight Lock)。这时线程使用 CAS 把对象头交换到自己的栈。如 CAS 失败,会进行重试(即自旋 Spin),重试多次仍然失败,升级到重量级锁(Heavyweight Lock),交给 OS 内核进行最终的同步处理。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 二、偏向锁被废弃 \color{blue}{二、偏向锁被废弃} </math>二、偏向锁被废弃

偏向锁只需要设置对象头的几个字段的值就能完成加锁,"性能很高"。但在 JDK15 中,偏向锁被默认关闭。在 JDK18 中,更被标记为废弃 ,并不再允许通过命令行手动开启。

看起来效果很好的偏向锁,为什么逐步被打入"冷宫"?OpenJDK 开发团队在 JEP 374 中解释:

过去看到的性能提升如今远没有那么明显。许多受益于偏向锁的程序都是较旧的遗留程序,它们使用早期的 Java 集合 API,它们在每次访问时进行同步(例如 HashtableVector )。对于较新的程序,针对单线程场景通常使用 Java 1.2 中引入的非同步集合(例如 HashMapArrayList ),针对多线程场景,则使用 Java 5 引入的性能更高的并发结构。这意味着,如果代码升级到这些较新的类,相比偏向锁,会有更大的性能提升。此外,围绕线程池队列和工作线程构建的应用程序通常在禁用偏向锁定的情况下性能更好。(例如,SPECjbb2015 就是这样设计的,而 SPECjvm98 和 SPECjbb2005 则不是)。

偏向锁定的代价是在发生锁争用时需要执行昂贵的撤销操作 。因此,受益于它的程序只是那些无竞争同步操作的程序。偏向锁的高效是假定在执行简单的锁检查加上偶尔昂贵的撤销成本,仍然低于执行 CAS 指令的成本。但 HotSpot 已经发生了很大的变化,原子指令成本的变化也改变了保持该关系所需的无竞争操作的数量。

另一个值得注意的方面是,当同步操作上花费的时间只占程序总工作负载的一小部分时,即使先前的成本关系成立,程序也不会从偏向锁中获得明显的性能改进。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 三、废弃原因分析 \color{blue}{三、废弃原因分析} </math>三、废弃原因分析

综合来看,偏向锁被废除主要有下面的原因:

3.1 可维护性差

JEP 374 中写到:

偏向锁在同步子系统中引入了大量复杂的代码,并且还会侵入其他 HotSpot 组件

为了实现偏向锁,在 JVM 中引入了大量代码 。并且,一个理想的代码库,应该做到"高内聚、低耦合",但偏向锁的代码和各个模块交叉耦合 ,相互影响。复杂的偏向锁实现给 OpenJDK 开发者造成了很大的负担,最终让他们不得不考虑放弃。

3.2 优化效果不好

OpenJDK 开发者统计到同步操作在程序实际运行中消耗的资源较少 ,即使偏向锁有一定提升,但对总体性能影响不大。另外,随着 JDK 并发数据结构(ConcurrentHashMap、CopyOnWriteArrayList等)和 CAS 操作的性能提升,偏向锁的作用很有限

3.3 前景不好

偏向锁优化效果不好,并且也没看到未来的优化空间。没有产出,也没有预期的产品很难长期存在。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 四、参考资料 \color{blue}{四、参考资料} </math>四、参考资料

相关推荐
Coder_Boy_1 分钟前
业务导向型技术日志首日记录(业务中使用的技术栈)
java·驱动开发·微服务
码事漫谈17 分钟前
国产时序数据库崛起:金仓凭什么在复杂场景中碾压InfluxDB
后端
上进小菜猪23 分钟前
当时序数据不再“只是时间”:金仓数据库如何在复杂场景中拉开与 InfluxDB 的差距
后端
盖世英雄酱581361 小时前
springboot 项目 从jdk 8 升级到jdk21 会面临哪些问题
java·后端
济南壹软网络科技有限公司1 小时前
企业级盲盒系统:Java高并发架构在多元化抽奖电商中的设计与实践
java·架构·开源源码·盲盒源码·盲盒h5·盲盒app
廋到被风吹走1 小时前
【Java】常用设计模式及应用场景详解
java·开发语言·设计模式
一条可有可无的咸鱼2 小时前
企业招聘信息,企业资讯进行公示
java·vue.js·spring boot·uni-app
程序猿DD2 小时前
JUnit 5 中的 @ClassTemplate 实战指南
java·后端
爱吃山竹的大肚肚2 小时前
EasyPOI 大数据导出
java·linux·windows
Victor3562 小时前
Netty(14)如何处理Netty中的异常和错误?
后端