我惊了!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

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

目录
相关文章
|
1月前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
63 1
|
5月前
|
监控 安全 Java
CompletableFuture探秘:解锁Java并发编程的新境界
CompletableFuture探秘:解锁Java并发编程的新境界
209 0
|
消息中间件 存储 Java
一网打尽异步神器CompletableFuture
最近一直畅游在RocketMQ的源码中,发现在RocketMQ中很多地方都使用到了CompletableFuture,所以今天就跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,并且最后会结合RocketMQ源码分析一下CompletableFuture的使用。
|
Java
异步利刃CompletableFuture
异步利刃CompletableFuture
96 0
|
JSON 缓存 JavaScript
提高系统吞吐量的一把利器:DeferredResult 到底有多强?
提高系统吞吐量的一把利器:DeferredResult 到底有多强?
CountDownLatch翻车后,大家都建议我用CompletableFuture改造下,改造完感觉真香啊!
前段时间使用了CountDownLatch来做并发流程的控制,在生产上碰到了一些问题,最终问题是解决了,但是那篇文章的评论大家让我用CompletableFuture来试一试,改造完之后,发现CompletableFuture这东西真强大,有种相见恨晚的感觉。
我惊了!CompletableFuture居然有性能问题! (下)
我惊了!CompletableFuture居然有性能问题! (下)
558 0
我惊了!CompletableFuture居然有性能问题! (下)
|
缓存 负载均衡 Dubbo
我惊了!CompletableFuture居然有性能问题! (上)
我惊了!CompletableFuture居然有性能问题! (上)
467 0
我惊了!CompletableFuture居然有性能问题! (上)
|
缓存 前端开发 Java
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(上)
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(上)
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(上)
|
Java API
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(下)
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(下)
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文(下)