延迟分析中的案例研究:锁定与同步
特别是在这篇文章中,我们将讨论:
- java.concurrent.Lock创建的垃圾
- 比较锁与同步
- 如何以编程方式测量延迟
- 争用对锁和同步的影响
- 协调遗漏对延迟测试的影响
回到我最喜欢的主题之一,垃圾创建/分配。 有关此主题的更多详细信息,请参阅我以前的文章(例如,性能优化 的第一条规则和重新访问 性能优化 的第一条规则:逃逸分析的效果 )。 特别是为什么分配是理解性能问题的如此关键因素。
几天前,在尝试诊断JIT编译过程中分配的一些奇怪影响时,我遇到了一个问题,即java.util.concurrent.locks.ReentrantLock
分配,但仅当处于竞争状态时才进行分配。 (这可以通过运行一个测试程序(如以下程序)轻松地证明,使用– verbosegc
在Lock上创建竞争)。
下面的竞争锁的gc输出示例:
[GC (Allocation Failure) 16384K->1400K(62976K), 0.0016854 secs]
[GC (Allocation Failure) 17784K->1072K(62976K), 0.0011939 secs]
[GC (Allocation Failure) 17456K->1040K(62976K), 0.0008452 secs]
[GC (Allocation Failure) 17424K->1104K(62976K), 0.0008338 secs]
[GC (Allocation Failure) 17488K->1056K(61952K), 0.0008799 secs]
[GC (Allocation Failure) 17440K->1024K(61952K), 0.0010529 secs]
[GC (Allocation Failure) 17408K->1161K(61952K), 0.0012381 secs]
[GC (Allocation Failure) 17545K->1097K(61440K), 0.0004592 secs]
[GC (Allocation Failure) 16969K->1129K(61952K), 0.0004500 secs][GC (Allocation Failure) 17001K->1129K(61952K), 0.0003857 secs]
我想知道清理这些分配所必需的垃圾回收是否意味着在高度竞争的环境中,与使用内置的“ synchronized
”相比, Lock
在同步方面是更糟糕的选择。
当然,这个问题比其他任何事情都更具学术性。 如果您确实非常在意延迟,那么您将永远(或者肯定永远不会)陷入需要大量线程锁定的情况。 不过,因为过程和结果很有趣,所以请和我在一起。
有点历史。 锁于2004年在Java 1.5版中引入。迫切需要将Lock
与其他并发实用程序一起使用,以简化并发构造。 到那时为止,您已经处理了Object
上的内置synchronized
和wait()notify()
。
ReentrantLock除了提供synchronized
功能外,还提供许多功能,
这仅仅是列举的一小部分:
- 非结构化–即您不限于在块或方法中使用它。 它使您可以通过几种方法持有锁。
- 锁定轮询
- 超时等待锁
- 可配置的公平政策
但是,它们在延迟测试方面的表现如何?
我在下面编写了一个简单的测试,比较了锁与同步的性能。
- 该代码使您可以更改线程数(1个线程表示没有争用),从而调整争用量。
- 在有或没有协同遗漏的情况下进行测量(请参阅以前的博客《协调遗漏的效果》 )
- 运行测试锁定或同步测试。
- 要记录我的结果,您会注意到我使用了
Histogram
类。 这是由彼得·劳瑞(Peter Lawrey)创建的。 你可以找到类为纪事核心在实用这里 。
import org.junit.Test;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockVsSync {private static final boolean COORDINATED_OMISSION = Boolean.getBoolean("coordinatedOmission");//Either run testing Lock or testing synchronizedprivate static final boolean IS_LOCK = Boolean.getBoolean("isLock");private static final int NUM_THREADS = Integer.getInteger("numThreads");@Testpublic void test() throws InterruptedException {Lock lock = new ReentrantLock();for (int t = 0; t < NUM_THREADS; t++) {if (t == 0) {//Set the first thread as the master which will be measured//The other threads are only to cause contentionRunner r = new Runner(lock, true);r.start();} else {Runner r = new Runner(lock, false);r.start();}}synchronized(this){//Hold the main thread from completingwait();}}private void testLock(Lock rlock) {rlock.lock();try {for (int i = 0; i < 2; i++) {double x = 10 / 4.5 + i;}} finally {rlock.unlock();}}private synchronized void testSync() {for (int i = 0; i < 2; i++) {double x = 10 / 4.5 + i;}}class Runner extends Thread {private Lock lock;private boolean master;public Runner(Lock lock, boolean master) {this.lock = lock;this.master = master;}@Overridepublic void run() {Histogram histogram = null;if (master)histogram = new Histogram();long rate = 1000;//expect 1 every microsecondlong now =0;for (int i = -10000; i < 200_000_000; i++) {if(i==0){now = System.nanoTime();} else if(i>0){if(!COORDINATED_OMISSION) {now += rate;while(System.nanoTime() < now);}elsenow = System.nanoTime();}if(IS_LOCK)testLock(lock);elsetestSync();if(i>=0 && master){histogram.sample(System.nanoTime() - now);}}if (master) {System.out.println(histogram.toMicrosFormat());System.exit(0);}}}
}
结果如下:
这些是忽略了遗漏的结果:
- 时间以微秒为单位。
- 延迟分布在图的顶部。
- 此测试中的争用意味着要使用4个线程运行该程序。
- 测试在具有8个逻辑CPU的MBP i7上运行。
- 每个测试包括200,000,000次迭代和10,000次迭代预热。
- 调整协调遗漏时的吞吐量为1迭代/微秒。
正如预期的那样,在没有争用的情况下,结果几乎相同。 JIT将优化锁定并进行同步。
在较低的百分位数中,使用Lock进行争用稍微快一些,但实际上又不是很多。 因此,即使有许多较小的垃圾收集,它们似乎也没有显着降低锁的速度。 如果有的话,总体上Lock会稍微快一点。
这些是为协调省略而调整的结果。
这些数字当然更高,因为它们考虑了引起的真正延迟。
同样,在没有争用的情况下,锁和同步执行相同的操作–在那里没有很大的惊喜。
有了争用,现在我们可以看到高达99%的百分比的同步锁定性能超出10倍。 之后,时间几乎相同。
我可以推测,与同步相比,gc集合的影响(介于300-1200微秒之间)是导致锁缓慢的原因。 尤其是因为速度下降仅出现到第99个百分位时才明显–在此之后,延迟可能会降到硬件和操作系统上。 但是,这只是我的推测,无需进一步调查。
结论
这篇文章的收获更多是关于衡量和分析延迟的过程。 有趣的是, Lock
在竞争时进行分配,但不太可能在现实世界中产生任何实际变化
翻译自: https://www.javacodegeeks.com/2015/08/a-case-study-in-analysing-latency-lock-vs-synchronized.html
延迟分析中的案例研究:锁定与同步相关推荐
- mac 大写锁定延迟_延迟分析中的案例研究:锁定与同步
mac 大写锁定延迟 特别是在这篇文章中,我们将讨论: java.concurrent.Lock创建的垃圾 比较锁与同步 如何以编程方式测量延迟 争用对锁和同步的影响 遗漏对延迟测试的影响 回到我最喜 ...
- 基因组关联分析中的交互作用研究
基因组关联分析中的交互作用研究 语音 编辑 讨论 上传视频 本词条缺少概述图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! <基因组关联分析中的交互作用研究>是依托中国科学技术大 ...
- 词云分析案例_品牌案例中的案例研究词
词云分析案例 A close-up look at Friday's design process. 近看星期五的设计过程. WORDS IN THE WILD IS A BAY-AREA NONPR ...
- chi-squared检验_每位数据科学家都必须具备Chi-S方检验统计量:客户流失中的案例研究
chi-squared检验 重点 (Top highlight) 介绍 (Introduction) The chi-square statistic is a useful tool for und ...
- 机器学习在行业应用中的案例研究
原文地址:http://www.msra.cn/zh-cn/research/machine-learning-group/machine-learning-for-industry-a-case-s ...
- java线程死锁_Java线程死锁–案例研究
java线程死锁 本文将描述从在IBM JVM 1.6上运行的Weblogic 11g生产系统中观察到的最新Java死锁问题的完整根本原因分析. 此案例研究还将证明掌握线程转储分析技能的重要性: 包括 ...
- Java线程死锁–案例研究
本文将描述从在IBM JVM 1.6上运行的Weblogic 11g生产系统中观察到的最新Java死锁问题的完整根本原因分析. 此案例研究还将证明掌握线程转储分析技能的重要性: 包括用于IBM JVM ...
- 解决一个典型的商业案例研究任务
介绍 印尼的一家公司 Gojek 通过移动应用程序提供运输和物流.食品和购物.支付.日常需求.商业.新闻和娱乐等服务,对经济做出了超过70亿美元的贡献. 它拥有 90 万注册商户.超过 1.9 亿次应 ...
- MySQL · 捉虫动态 · UK 包含 NULL 值备库延迟分析
前言 在之前的月报 RDS 只读实例延迟分析 中,我们介绍了一些常见的备库延迟的场景,今天给大家分享一个比较少见的特殊场景. 简单的来说,就是在 UK 索引中存在大量 NULL 值情况下,如果备库选用 ...
最新文章
- 域名管理系统 二级域名_域名系统简介
- 撸了个低代码开发平台,爽!
- 确定第十五届安徽赛区国赛奖项数量
- macOs下全局安装npm包的设置问题
- Flex Application里的addChild()
- 矩阵正态分布基础1 外形式、外积与微分形式简介
- 128核云原生新力作:Ampere® Altra® Max性能参数公布,提升50%!
- 【IntelliJ IDEA】使用idea解决新建jsp文件而找不到jsp文件模版的新建选项
- mysql添加序列触发器_Oracle中使用触发器(trigger)和序列(sequence)模拟实现自增列实例...
- CVE-2014-6332 修改浏览器安全属性开启Godmode
- php curl获取404,php使用curl判断网页404(不存在)的方法
- 计算机一级考试搜题app,计算机一级考试题库答案,哪个搜题软件能找到?
- vue项目中使用 echarts 创建一个关系图
- 家谱排版制作软件怎么三步成谱
- nginx搭建flv、mp4流媒体服务器
- ORACLE百例试炼五
- 关于刚毕业的程序员考取mba
- [IMX6Q][Android5.1]移植笔记 --- 无法挂载system文件系统
- linux进程假死的原因_Linux系统死机的原因及解决办法
- 狼的故事11:以牙还牙
热门文章
- python爬虫进阶(初始)
- ssm(Spring+Spring mvc+mybatis)Spring配置文件——applicationContext-servlet.xml
- ssh(Spring+Spring mvc+hibernate)——EmpController
- 2020蓝桥杯省赛---java---B---7(单词分析)
- 廖雪峰python教程整理笔记_廖雪峰python教程笔记(一)
- android菱形imageview,ios – 在UICollectionView中,UIImageView应该是圆形视图而不是菱形...
- shell脚本启动kafka集群的多台节点
- java6 已安装更高版本_Java 10及更高版本的思考
- java创建一个不可变对象_使用不可变对象创建值对象
- java 函数式编程_Java函数式编程:Javaslang入门