但是后面跟了一个“problem”,这个“problem”就是说如果我们把多处理器这个值缓存起来了,假设程序运行的过程中出现了从多处理器到单处理器的运行环境变化这个值就不准确了,虽然这是一个不太可能的变化。但是即使这个“problem”真的发生了也没有关系,它只是会导致一个小小的性能损失。
所以就出现了前面大家看到的这样的代码,这就是 “we can cache this value in a field”:
而体现到具体的代码变更是这样的:
所以,当你去看这部分源码的时候,你会看到 SPINS 字段上其实还有很长一段话,是这样的:
给大家翻译一下:
1.在 waitingGet 方法中,进行阻塞操作前,进行旋转。
2.没有必要在单处理器上进行旋转。
3.调用 Runtime.availableProcessors 方法的成本是很高的,所以在此缓存该值。但是这个值是首次初始化时可用的 CPU 的数量。如果某系统在启动时只有一个 CPU 可以用,那么 SPINS 的值会被初始化为 0,即使后面再使更多的 CPU 在线,也不会发生变化。
当你有了前面的 BUG 的描述中的铺垫之后,你就明白了为什么这里写上了这么一大段话。
有的同学就真的去翻代码,也许你看到的是这样的:
什么情况?根本就看不到 SPINS 相关的代码啊,这不是欺骗老实人吗?
你别慌啊,猴急猴急的,我这不是还没说完嘛?
我们再把目光放到图片中的这句话上:
只需要在 JDK 8 中进行这个修复即可,因为 JDK 9 和更高版本的代码都不是这样的写的了。
比如在 JDK 9 中,直接拿掉了整个 SPINS 的逻辑,不要这个短暂的自旋等待了:
虽然,拿掉了这个短暂的自旋等待,但是其实也算是学习了一个骚操作。
问:怎么在不引入时间的前提下,做出一个自旋等待的效果?
答案就是被拿掉的这段代码。
但是有一说一,我第一次看到这个代码的时候我就觉得别扭。这一个短短的自旋能延长多少时间呢?
加入这个自旋,是为了稍晚一点执行后续逻辑中的 park 代码,这个稍重一点的操作。但是我觉得这个 “brief spin-wait” 的收益其实是微乎其微的。
所以我也理解为什么后续直接把这一整坨代码拿掉了。而拿掉这一坨代码的时候,其实作者并没有意识到这里有 BUG。
而这里提到的作者,其实就是 Doug Lea 老爷子。
我为什么这样说呢?
依据就在这个 BUG 链接里面提到的编号为 8227018 的 BUG 中,它们其实描述的是同一个事情:
Holmes 在这里面提到了 “cache this value in a field” 的解决方案,并得到了 Doug 的同意。
Doug 说: JDK 9 已经不用 spin 了。
所以,我个人理解是 Doug 在不知道这个地方有 BUG 的情况下,拿掉了 SPIN 的逻辑。至于是出于什么考虑,我猜测是收益确实不大,且代码具有一定的迷惑性。还不如拿掉之后,理解起来直观一点。
Doug Lea 大家都耳熟能详, David Holmes 是谁呢?
《Java 并发编程实战》的作者之一,端茶就完事了。
而你要是对我以前的文章印象足够深刻,那么你会发现早在《Doug Lea在J.U.C包里面写的BUG又被网友发现了。》这篇文章里面,他就已经出现过了:
老朋友又出现了,建议铁汁们把梦幻联动打在公屏上。