Java高并发- 锁的优化及 JVM 对锁优化所做的努力

2023-11-03

在高并发环境下,激烈的锁竞争会导致程序的性能下降,所以我们有必要讨论一下有关 锁 的性能问题及注意事项。如:避免死锁,减小锁粒度,锁分离等。

一、锁优化

1.1 减小锁持有时间
在锁竞争过程中,单个线程对锁的持有时间与系统性能有着直接的关系,如果线程持有锁的时间很长,那么相对地,锁的竞争程序也就越激烈。
示例代码:

public void syncMethod(){
fun1();
mutextMethod();
fun2();
}

在 syncMethod 方法中,假设只有 mutextMethod() 方法需要同步,而 fun1() 和 fun2() 不需要同步。如果 fun1() 和 fun2() 分别是重量级的方法,则会花费较大的 CPU 时间。此时如果在并发量较大,使用这种对整个方法做同步的方案,会导致等待线程大量增加。
一个较为优化的方案是,只在必要时进行同步,这样就能明显减少线程持有锁的时间,提高系统吞吐量。

public void syncMethod(){
fun1();
synchronized(this){
mutextMethod();
}
fun2();
)

在改进的代码中,只针对 mutextMethod 方法做同步,锁占用时间相对较短,因此能提高并行度。这种技术手段在 JDK 的源码总也可以嗯容易找到,如处理正则表达式的 Pattern 类:

public Matcher matcher(CharSequence input){
if(!compiled){
synchronized(this){
if(!compiled){
compile();
}
}
}
Matcher m = new Matcher(this,input);
return m;
}

matcher() 方法有添加的进行锁申请,只有在表达式未编译时,进行局部加锁。这种处理大大提高了 matcher() 方法的执行效率和可靠性。
注意:减小锁的持有时间有助于降低锁冲突的可能性,进而提升系统的并发能力。
1.2 减小锁力度
减小锁力度也是一种削弱多线程锁竞争的有效手段,这种技术的使用场景就是 ConcurrentHashMap 类的实现。
ConcurrentHashMap 不是直接锁住整个 HashMap,而是在 ConcurrentHashMap 内部进一步细分了若干个小的 HashMap,称之为段(Segment)。在 ConcurrentHashMap 中,无论是读操作还是写操作都能保证很高的性能:在进行读操作时 (几乎) 不需要加锁,而在写操作时通过锁分段技术只对所操作的段加锁而不影响客户端对其它段的访问。特别地,在理想状态下,ConcurrentHashMap 可以支持 16 个线程执行并发写操作(如果并发级别设为16),及任意数量线程的读操作。
注意:所谓减小锁粒度,就是缩小锁对象的范围,从而减少锁冲突的可能性,进而提高系统的并发能力。
1.3 读写分离锁类代替独占锁
读写锁 ReentrantReadWriteLock 可以提高系统性能,使用读写分离锁来替代独占锁是减小锁粒度的一种特殊情况。读操作本身不会影响数据的完整性和一致性,因此,大部分情况下,可以允许多线程同时读,读写锁正是实现了这种功能。
注意:在读多写少的场合,使用读写锁可以有效提升系统并发能力。
1.4 锁分离
将读写锁思想进一步延伸,就是锁分离。读写锁根据读写操作功能上的不同,进行了有效的锁分离。根据应用程序的功能特点,使用类似的分离思想,也可以对独占锁进行分离。
典型案例就是 LinkedBlockingQueue 的实现,take() 和 put() 分别实现了从队列中取得数据和往队列中增加数据的功能。虽两个数据都对当前队列进行了修改操作,但由于 LinkedBlockingQueue 是基于链表的,因此两个操作分别作用于队列的前端和尾端。
如果使用独占锁,则要求在两个操作进行时获取当前队列的独占锁,那么 take() 和 put() 操作不可能真正的并发,在运行时,它们会彼此等待对方释放资源。这种情况下,锁竞争会相对比较激烈,从而影响呈现的高并发时的性能。
在 JDK 实现中,采用的是分离锁思想,使用了两把不同的锁,分离 take() 和 put() 操作。

/** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();
 /** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
     /** Lock held by put, offer, etc */
    private final ReentrantLock putLock = new ReentrantLock(); 
    /** Wait queue for waiting puts */
    private final Condition notFull = putLock.newCondition();

上面的代码定义了 takeLock 和 putLock 分别在 take() 和 put() 操作中使用,因此 take() 和 put() 相对独立,它们之间不存在锁竞争关系,只需要在 take() 和 take() 之间,put() 和 put() 之间分别对 takeLock 和 putLock 进行竞争。

public E take()throws InterruptedException{
   
E x
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java高并发- 锁的优化及 JVM 对锁优化所做的努力 的相关文章

  • java.library.path 中没有字体管理器

    以下代码在我的桌面上运行得很好 BufferedImage image new BufferedImage width height BufferedImage TYPE INT RGB Graphics g image getGraphi
  • 一个好的 Java VM 中方法调用的开销是多少?

    有人可以提供反汇编的机器代码汇编程序列表吗 我的意思是 与 C 中的普通函数调用相比 肯定有一些开销 VM 需要跟踪调用以查找热点 并且当它使用编译代码时 如果新加载的类需要重新编译 它需要提供动态更改编译方法的方法 我想某处也有返回堆栈溢
  • JVM 是否会内联对象的实例变量和方法?

    假设我有一个非常紧密的内部循环 每次迭代都会访问和改变一个簿记对象 该对象存储有关算法的一些简单数据 并具有用于操作它的简单逻辑 簿记对象是私有的和最终的 并且它的所有方法都是私有的 最终的和 inline 下面是一个示例 Scala 语法
  • 为什么不在下一个 JVM 中删除类型擦除呢?

    Java 在 Java 5 中引入了泛型类型擦除 因此它们可以在旧版本的 Java 上运行 这是兼容性的权衡 我们已经失去了这种兼容性 1 https stackoverflow com questions 22610400 a progr
  • 如何判断我是在 64 位 JVM 还是 32 位 JVM 中运行(在程序内)?

    如何判断应用程序运行的 JVM 是 32 位还是 64 位 具体来说 我可以使用哪些函数或属性来在程序中检测到这一点 对于某些版本的 Java 您可以使用标志从命令行检查 JVM 的位数 d32 and d64 java help d32
  • JVM内存段分配

    好吧 我有一个关于 JVM 内存段的问题 我知道每个 JVM 都会选择稍微不同地实现这一点 但这是一个总体概念 在所有 JVM 中应该保持相同 一个在运行时不使用虚拟机执行的标准C C 程序在运行时有四个内存段 代码 堆栈 堆 数据 所有这
  • Bipush 在 JVM 中如何工作?

    我知道 iload 接受整数 1 到 5 但是如何使用 bipush 指令扩展到更高的数字 特定整数如何与字节码一起存储 有几种不同的指令可用于推送整数常量 最小的是iconst 指令 这些只是一个字节 因为该值是在操作码本身中编码的 ic
  • OQL 包中的所有实例

    是否有可能在OQL检索属于一个包的所有对象 或者我可以查询wildcards 正如 haridsv 建议我尝试过的 SELECT from com example and SELECT a from com example but in V
  • Java 中清除嵌套 Map 的好方法

    public class MyCache AbstractMap
  • Kotlin 未解决的参考:CLI 上 gradle 的 println

    放一个printlnkotlin 函数返回之前的语句会崩溃 堆栈跟踪 thufir dur NetBeansProjects kotlin thufir dur NetBeansProjects kotlin gradle clean bu
  • jvm 次要版本与编译器次要版本

    当运行使用具有相同主要版本但次要版本高于 JVM 的 JDK 编译的类时 JVM 会抛出异常吗 JDK 版本并不重要 类文件格式版本 http blogs oracle com darcy entry source target class
  • 容器中的 JVM 计算处理器错误?

    最近我又做了一些研究 偶然发现了这一点 在向 OpenJDK 团队抱怨之前 我想看看是否有其他人观察到这一点 或者不同意我的结论 因此 众所周知 JVM 长期以来忽略了应用于 cgroup 的内存限制 众所周知 现在从 Java 8 更新某
  • 测量 tomcat 的排队请求数

    因此 使用tomcat 您可以设置acceptCount值 默认为100 这意味着当所有工作线程都忙时 新连接被放置在队列中 直到队列满 之后它们被拒绝 我想要的是监视此队列中项目的大小 但无法确定是否有办法通过 JMX 获取此值 即不是队
  • 无法为对象堆保留足够的空间

    每次尝试运行该程序时 我都会重复出现以下异常 VM初始化期间发生错误 无法为对象堆保留足够的空间 无法创建Java虚拟机 我尝试增加虚拟内存 页面大小 和 RAM 大小 但无济于事 我怎样才能消除这个错误 运行 JVM XX MaxHeap
  • Java中的整数缓存[重复]

    这个问题在这里已经有答案了 可能的重复 奇怪的Java拳击 https stackoverflow com questions 3130311 weird java boxing 最近我看到一个演示 其中有以下 Java 代码示例 Inte
  • ASM之前看一下maxStack指令吗?

    我正在尝试使用 ASM 库将字节代码转换为不同的格式 这可以使用 MethodVisitor 来完成 就像这个简单的测试代码一样 return new MethodVisitor ASM7 Override public void visi
  • Android java.exe 以非零退出值 1 结束 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我尝试过查看类似的解决方案 但没有解决方案有效 我以前运行应用程序没有问题 但我的新应用程序突然开始给我带来问题 当我尝试运行它时总是
  • Java 堆分析因 SIGABRT 崩溃

    我正在尝试分析由 C 编写的方法分配并插入的本机内存JVM通过JNI 我安装了 valgrind version valgrind 3 13 0 并尝试使用以下选项运行 JVM valgrind tool massif massif out
  • 为什么java(>=7版本)不支持运行没有main方法的程序? [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 class WithoutMain static System out println Without main class Sy
  • 使用 jni 从 C 调用 java 函数

    我正在编写一个简单的程序来从我的 C 程序调用 Java 函数 以下是我的代码 include

随机推荐

  • AI焦虑潮下,打工人的抵抗、转向、破局

    一股 AI让人下岗 的焦虑 正在蔓延 蔓延到了 这里 不同于区块链 元宇宙和web3 2023年的这股AI浪潮真正席卷了所有人 在大厂 大佬和投资人们为船票激烈角逐的同时 Midjouney ChatGPT Notion AI等工具的惊人效
  • 闲鱼副业是什么?闲鱼副业应该怎么做?

    闲鱼副业是什么 闲鱼副业应该怎么做 有人会问 闲鱼现在还能做吗 还能赚钱吗 对于这样的问题 我只想说 其实再不好的行业 都有赚钱的牛人 再赚钱的领域 同样也有挣不到钱的人 所以 对于赚钱 有一句话是这样说的 没有不赚钱的项目 只有不会赚钱的
  • GPT专业应用:撰写工作简报

    图片由Lexica 生成 输入 Workers working overtime 工作简报 作为一种了解情况 沟通信息的有效手段 能使上级机关和领导及时了解 掌握所属部门的政治学习 军事训练 行政管理等方面的最新情况 同时 能和同级单位 部
  • FLEX & BISON 联合使用

    flex是词法分析器 bison是语法分析器 基本原理就是flex解析出token后 让bison来使用 实际上 一般是先编写bison脚本 里面的token就是一个定义 没有实现 里面的yylex也是没有实现 只有定义 为什么先做biso
  • 路由(route) 交换机(switch)简介

    路由 route 1 数据包从源地址到目的地址所经过的路径 由一系列路由节点组成 2 某个路由节点为数据包选择投递方向的选路过程 它是连接因特网中各局域网 广域网的设备 一 工作原理 工作于OSI七层协议中的第三层 接收来自一个网络接口的数
  • 租赁行业如何将电子合同活用起来?

    在租赁行业 采取传统纸质合同签署租赁类合同 需要相关人员全部在场签订 效率低下 随着互联网行业的发展 租房 租车等各种租赁类业务逐渐迁移到了线上 互联网租赁平台也因此应运而生 但也带来了各种问题 身份核实困难 中介越过平台做私单 诈骗租赁物
  • 线性代数 --- LU分解(Gauss消元法的矩阵表示)

    Gauss消元法等价于把系数矩阵A分解成两个三角矩阵L和U的乘法 首先 LU分解实际上就是用矩阵的形式来记录的高斯消元的过程 其中 对矩阵A进行高斯消元后的结果为矩阵U 是LU分解后的两个三角矩阵中其中之一 U是一个上三角矩阵 U就是上三角
  • elasticsearch 5.x删除index/type

    elasticsearch 5 x删除index 在head插件中执行 DELETE ip port index 看到 acknowledge true 即为成功 elasticsearch 5 x删除type 在kibana界面 dev
  • java 参数明明名字都是对的为什么值传不过来

    java 参数明明名字都是对的为什么值传不过来 那是因为值的类型不一样 导致匹配不上 一个是long 一个是string
  • C++数据结构笔记(3)线性表的链式存储底层实现

    本系列的帖子并不包含全部的基础知识 只挑一部分最核心的知识点总结 着重于具体的实现细节而并非理论的知识点总结 大家按需阅读学习 链表的核心概念总结如下 1 链式存储不需要连续的内存空间 2 链表由一系列的结点组成 每个节点包含两个域 分别是
  • Unity获得当前场景所有物体

    前言 1 GameObject FindObjectsOfType typeof GameObject 只能获得所有active物体 2 GameObject FindObjectsOfTypeAll该方法已过时 解决方案 可以使用Reso
  • 定义一个Student类,成员变量有姓名、年龄;用数组存5个学生对象,并输出

    public class Student String name int age public Student String name int age this name name this age age public class tex
  • IntersectionObserver实现图片懒加载(超详细!)

    关于IntersectionObserver 官方上说明是提供了一种异步观察目标元素与其祖先元素或顶级文档视窗 viewport 交叉状态的方法 祖先元素与视窗 viewport 被称为根 root 具体的内容可以参考官网解释 https
  • 前端三小时用html和js写一个贪吃蛇游戏,非常简单带讲解,代码可直接用,功能完整

    目录 游戏主体部分 普通模式 游戏主体部分 地狱模式 游戏主页入口 预览图 游戏入口代码 1 html 2 css 3 js 注册页面代码 游戏实现很简单 只写游戏主体的话只要三小时就够了 话不多说 我们直接来看效果预览 转成gif图之后有
  • MATLAB读dat文件中存储的十六进制数

    搞了好久都没搞懂为什么MATLAB里load textread都打不开区区一个十六进制文件 经过不懈的寻找 发现fopen fread就是永远滴神 果然灯下黑 data zeros 1 1000 fid fopen 1 dat rb row
  • 云服务器有比虚拟主机好吗,云服务器有比虚拟主机好吗

    云服务器有比虚拟主机好吗 内容精选 换一换 在高可用部署场景下 ASCS主备节点通过共享盘实现数据同步 本章节指导用户将ASCS主节点的数据盘绑定给ASCS备节点并为ASCS主备节点绑定浮动IP 已在SAP ASCS主备节点之间进行过相互的
  • 大数据学习之Hive——05Hive函数

    一 内置函数 1 数学函数 Return Type Name Signature Description DOUBLE round DOUBLE a 返回对a四舍五入的BIGINT值 DOUBLE round DOUBLE a INT d
  • 网页上文本框禁止复制粘贴怎么破解

    我们首先来介绍如何实现禁止复制 知道了禁止的方式 再破解就容易了 实现禁止复制粘贴 比较简单 直接上代码 h1 本代码在UC手机浏览器上不生效 其它手机浏览器暂未发现问题 PC全部没问题 h1 p p
  • uniapp swiper轮播图片+视频

    1 效果 2 代码展示
  • Java高并发- 锁的优化及 JVM 对锁优化所做的努力

    在高并发环境下 激烈的锁竞争会导致程序的性能下降 所以我们有必要讨论一下有关 锁 的性能问题及注意事项 如 避免死锁 减小锁粒度 锁分离等 一 锁优化 1 1 减小锁持有时间 在锁竞争过程中 单个线程对锁的持有时间与系统性能有着直接的关系