我惊了!CompletableFuture居然有性能问题! (中)

简介: 我惊了!CompletableFuture居然有性能问题! (中)

但是后面跟了一个“problem”,这个“problem”就是说如果我们把多处理器这个值缓存起来了,假设程序运行的过程中出现了从多处理器到单处理器的运行环境变化这个值就不准确了,虽然这是一个不太可能的变化。但是即使这个“problem”真的发生了也没有关系,它只是会导致一个小小的性能损失。

所以就出现了前面大家看到的这样的代码,这就是 “we can cache this value in a field”:

image.png

而体现到具体的代码变更是这样的:

http://cr.openjdk.java.net/~shade/8227018/webrev.01/src/share/classes/java/util/concurrent/CompletableFuture.java.udiff.html


image.png

所以,当你去看这部分源码的时候,你会看到 SPINS 字段上其实还有很长一段话,是这样的:

image.png

给大家翻译一下:

1.在 waitingGet 方法中,进行阻塞操作前,进行旋转。

2.没有必要在单处理器上进行旋转。

3.调用 Runtime.availableProcessors 方法的成本是很高的,所以在此缓存该值。但是这个值是首次初始化时可用的 CPU 的数量。如果某系统在启动时只有一个 CPU 可以用,那么 SPINS 的值会被初始化为 0,即使后面再使更多的 CPU 在线,也不会发生变化。

当你有了前面的 BUG 的描述中的铺垫之后,你就明白了为什么这里写上了这么一大段话。

有的同学就真的去翻代码,也许你看到的是这样的:

image.png

什么情况?根本就看不到 SPINS 相关的代码啊,这不是欺骗老实人吗?

image.png

你别慌啊,猴急猴急的,我这不是还没说完嘛?

我们再把目光放到图片中的这句话上:

image.png

只需要在 JDK 8 中进行这个修复即可,因为 JDK 9 和更高版本的代码都不是这样的写的了。

比如在 JDK 9 中,直接拿掉了整个 SPINS 的逻辑,不要这个短暂的自旋等待了:

http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/f3af17da360b


image.png


虽然,拿掉了这个短暂的自旋等待,但是其实也算是学习了一个骚操作。

问:怎么在不引入时间的前提下,做出一个自旋等待的效果?

答案就是被拿掉的这段代码。

但是有一说一,我第一次看到这个代码的时候我就觉得别扭。这一个短短的自旋能延长多少时间呢?

加入这个自旋,是为了稍晚一点执行后续逻辑中的 park 代码,这个稍重一点的操作。但是我觉得这个 “brief spin-wait” 的收益其实是微乎其微的。

所以我也理解为什么后续直接把这一整坨代码拿掉了。而拿掉这一坨代码的时候,其实作者并没有意识到这里有 BUG。

而这里提到的作者,其实就是 Doug Lea 老爷子。

我为什么这样说呢?

依据就在这个 BUG 链接里面提到的编号为 8227018 的 BUG 中,它们其实描述的是同一个事情:

image.png

image.png


Holmes 在这里面提到了 “cache this value in a field” 的解决方案,并得到了 Doug 的同意。

Doug 说: JDK 9 已经不用 spin 了。

所以,我个人理解是 Doug 在不知道这个地方有 BUG 的情况下,拿掉了 SPIN 的逻辑。至于是出于什么考虑,我猜测是收益确实不大,且代码具有一定的迷惑性。还不如拿掉之后,理解起来直观一点。

Doug Lea 大家都耳熟能详, David Holmes 是谁呢?


image.png


《Java 并发编程实战》的作者之一,端茶就完事了。


image.png


而你要是对我以前的文章印象足够深刻,那么你会发现早在《Doug Lea在J.U.C包里面写的BUG又被网友发现了。》这篇文章里面,他就已经出现过了:

image.png

老朋友又出现了,建议铁汁们把梦幻联动打在公屏上。

目录
相关文章
|
7月前
|
Arthas 运维 监控
Arthas monitor(方法执行监控)
Arthas monitor(方法执行监控)
526 0
|
关系型数据库 MySQL 调度
DataX教程(05)- DataX Web项目实践
DataX教程(05)- DataX Web项目实践
2643 0
|
Java Maven 开发者
@EnableFeignClients:简化微服务间调用的艺术
@EnableFeignClients:简化微服务间调用的艺术
1864 2
|
安全 Java 数据安全/隐私保护
Spring Boot中的数据加密与解密
Spring Boot中的数据加密与解密
|
Java API
惊呆了!Java文件操作竟能如此简单:一分钟学会读写、复制、删除!
【6月更文挑战第27天】Java编程中的文件操作简单易行。使用`java.io`包中的`FileInputStream`和`FileOutputStream`进行读写,例如写文件将字符串转为字节写入,读文件则循环读取字节。文件复制涉及两个流,从源文件读取后写入目标文件。删除文件只需调用`File`对象的`delete`方法。这些基本操作让Java文件处理变得直观且易于掌握。
151 1
|
SQL XML 缓存
Mybatis源码分析 2:解析XML并映射到Sql
# XMLStatementBuilder:对单个XNode节点进行解析,得到具体的SqlSource并以此生成MappedStatement ## parseStatementNode方法: ```JAVA private final MapperBuilderAssistant builderAssistant; // 记录了当前mapper的namespace等基础信息 private
487 0
Mybatis源码分析 2:解析XML并映射到Sql
|
SQL Oracle 关系型数据库
如何使用 DATAX 以 UPSERT 语义更新下游 ORACLE 数据库中的数据?
如何使用 DATAX 以 UPSERT 语义更新下游 ORACLE 数据库中的数据?
|
JSON Java DataX
DataX教程(04)- 配置完整解读
DataX教程(04)- 配置完整解读
4008 0
|
存储 SQL JSON
5、DataX(DataX简介、DataX架构原理、DataX部署、使用、同步MySQL数据到HDFS、同步HDFS数据到MySQL)(一)
5、DataX(DataX简介、DataX架构原理、DataX部署、使用、同步MySQL数据到HDFS、同步HDFS数据到MySQL)(一)