开启偏向锁一定性能更好吗?

2023-10-21 23:30

本文主要是介绍开启偏向锁一定性能更好吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、背景

最近工作中遇到由于使用偏向锁导致性能下降的案例。
趁机总结下偏向锁的概念和锁的升级过程,以及重点聊下偏向锁是否会让性能更优化。

二、偏向锁

偏向锁是Java 6之后加入的一种针对加锁操作的优化手段,它是基于:在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得。因此,为了减少同一线程获取锁的代价(会涉及到一些CAS操作,耗时),引入了偏向锁。

偏向锁的工作原理是:当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程再次进入同步块时,无需再做任何同步操作。这样就省去了大量有关锁申请和释放的操作,从而提高程序的运行效率。
在这里插入图片描述

当有另一个线程试图访问同步块时,偏向模式就宣告结束。根据对象头里记录的信息判断是否需要撤销偏向。如果需要撤销,则等待原来的线程进入安全点(safepoint),然后暂停它,并清除对象头和栈帧中的相关信息。撤销之后重新竞争获取轻量级锁。

三、锁升级

锁的升级过程是这样的:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁。这个过程是不可逆的,这么做是为了提高同步的性能。

偏向锁阶段
当一个线程第一次访问一个同步块时,会在对象头和栈帧中记录线程ID,这时对象处于偏向锁状态。如果后续没有其他线程竞争该对象,那么该线程再次进入同步块时就无需再做任何同步操作。

升级轻量级锁
如果有另一个线程试图获取该对象的锁,那么偏向锁就会被撤销,并升级为轻量级锁。轻量级锁是通过 CAS 操作在对象头中设置一个指向栈中锁记录的指针来实现的。如果CAS 成功,那么当前线程就获得了轻量级锁;如果CAS失败,说明有多个线程竞争该对象,那么轻量级锁就会升级为重量级锁。

升级重量级锁
重量级锁是通过在对象头中设置一个指向重量级监视器(monitor)的指针来实现的。重量级监视器会阻塞所有未获得该对象的线程,并唤醒其中一个等待线程来获取该对象。这样就避免了多个线程不断自旋消耗CPU资源 。

特殊情况
在这里插入图片描述

hashCode 并不是初始就写在对象头的,而是第一次调用 hashCode 方法时写入的。
如果一个对象没有获取偏向锁前调用 hashCode 方法,则进入普通无锁状态并存储 hashCode。
当已经获取偏向锁后调用 hashCode 或 wait 方法,则直接竞争重量级锁。
详情参见:《HashCode方法的调用对Java锁的影响》

四、偏向锁性能更好?

通过前面的介绍,我们不难知道:

偏向锁性能更好的情况是,当一个对象只有一个线程访问,并且不会有其他线程竞争该对象时。这样,偏向锁可以完全取消同步操作,只需要在第一次获取锁时进行一次CAS操作,之后就可以直接进入同步块。

但是,如果一个对象经常被多个线程竞争,那么偏向锁就会频繁地撤销和恢复,增加了额外的开销。这种情况下,使用轻量级锁或重量级锁可能更合适。

不知道大家有没有留意自己的服务器的 JVM 参数配置,有些高并发的服务,开启偏向锁后会因为偏向锁频繁撤销导致系统停顿时间增加,偏向锁的撤销需要等待全局安全点(safe point),暂停持有偏向锁的线程,检查持有偏向锁的线程状态。

Java在JDK1.6 以后默认已经开启了偏向锁这个优化,JDK15 中,偏向锁被默认禁用了,偏向锁带来的加锁时性能提升从实际效果上看并不明显,不再推荐使用,最终将被废弃。

Biased locking introduced a lot of complex code into the synchronization subsystem and is invasive to other HotSpot components as well. This complexity is a barrier to understanding various parts of the code and an impediment to making significant design changes within the synchronization subsystem. To that end we would like to disable, deprecate, and eventually remove support for biased locking.

如果你想手动开启或关闭偏向锁,你可以使用 -XX:+UseBiasedLocking -XX:-UseBiasedLocking 参数来控制。

Applications with substantial amounts of uncontended synchronization may attain significant speedups while others with certain patterns of locking may see slowdowns.

一句话结论:一般来说面向C 端的,并发较高的应用,尽量关闭偏向锁;面向 B 端的,并发较低的应用,可以考虑开启偏向锁。

五、More

很多人说:“面试造火箭,入职拧螺丝”。
但工作中真正遇到疑难杂症时,还是这些造火箭的知识更能解决问题。
学习不是目的,学习的目的还是为了:”学以致用“。
大家学习某个技术时,要了解某项技术解决什么问题,优缺点是什么。

每个问题都是我们深入掌握某个知识点的绝佳机会。当你工作中遇到问题时,一定要有寻根究底的态度,趁机掌握好相关知识,才能不断增加技术深度。

学任何知识都要比一般人掌握更多才能更具有优势。对于偏向锁而言,不仅要知道概念,还要知道为什么提供这种特性,什么情况下使用,进一步了解锁的升级过程,了解锁升级的特殊情况等。

六、参考文章

[1] 《25 张图 | 深入浅出「偏向锁》」
[2] 《HashCode方法的调用对Java锁的影响》
[2] 《Java 6 性能白皮书》
[3] JEP 374: Deprecate and Disable Biased Locking

这篇关于开启偏向锁一定性能更好吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/257641

相关文章

mysql线上查询之前要性能调优的技巧及示例

《mysql线上查询之前要性能调优的技巧及示例》文章介绍了查询优化的几种方法,包括使用索引、避免不必要的列和行、有效的JOIN策略、子查询和派生表的优化、查询提示和优化器提示等,这些方法可以帮助提高数... 目录避免不必要的列和行使用有效的JOIN策略使用子查询和派生表时要小心使用查询提示和优化器提示其他常

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

Tomcat高效部署与性能优化方式

《Tomcat高效部署与性能优化方式》本文介绍了如何高效部署Tomcat并进行性能优化,以确保Web应用的稳定运行和高效响应,高效部署包括环境准备、安装Tomcat、配置Tomcat、部署应用和启动T... 目录Tomcat高效部署与性能优化一、引言二、Tomcat高效部署三、Tomcat性能优化总结Tom

开启mysql的binlog日志步骤详解

《开启mysql的binlog日志步骤详解》:本文主要介绍MySQL5.7版本中二进制日志(bin_log)的配置和使用,文中通过图文及代码介绍的非常详细,需要的朋友可以参考下... 目录1.查看是否开启bin_log2.数据库会把日志放进logs目录中3.查看log日志总结 mysql版本5.71.查看

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

idea如何开启菜单栏

《idea如何开启菜单栏》文章介绍了如何通过修改IntelliJIDEA的样式文件`ui.lnf.xml`来重新显示被关闭的菜单栏,并分享了解决问题的步骤... 目录ijsdea开启菜单栏第一步第二步总结idea开启菜单栏手贱关闭了idea的js菜单栏,花费了半个小时终于解决,记录并分享一下第一步找

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题