我了解到在 Java 中递增 int 变量不是原子操作,但是,我发现 CPU 支持原子 Fetch-and-Increment
操作。
所以我的问题是,为什么 JVM 不将 incrementing a int variable
操作编译为 CPU 支持的原子 Fetch-and-Increment
操作,这可能很有用在多线程编程中。
Early processors had atomic test-and-set,
fetch-and-increment
, or swap instructions sufficient for implementing mutexes that could in turn be used to implement more sophisticated concurrent objects.--Java Concurrency in Practice
最佳答案
So my question is, why JVM doesn't compile incrementing a int variable operation to an atomic Fetch-and-Increment operation that CPUs support, which could be useful in multi-thread programming.
因为在典型的现代 CPU 上,原子读取-修改-写入操作(例如递增)比其相应的非原子操作昂贵数十倍。而且它不会提供任何好处——代码不能依赖原子操作,因为不能保证它们是原子的。那么有什么好处呢?
虽然它与您的问题没有直接关系,因为很多其他人对此有错误的解释,但我将解释原子增量和非原子增量之间的两个区别(在硬件级别):
原子增量不能与同一核心中的某些其他操作重叠。也就是说,它必须在某个特定时间发生。这意味着 CPU 指令流水线通常会受到原子操作的严重负面影响。
为了防止另一个线程在我们的原子操作中间(读取和写入之间)重叠对同一缓存行的操作,缓存行在原子操作期间被锁定。如果另一个内核试图从执行原子操作的 CPU 中获取缓存行,即使是非原子操作,它也必须等到原子操作完成。 (这曾经是一个总线锁。现代 CPU 更加智能。)
当然,不能保证每个 CPU 都是一样的,但具有多核和流行的 Java 实现的现代 CPU 几乎肯定具有高度优化的多核操作。当然, future 的 CPU 可能会更好。
另外,要纠正另一个常见的误解:现代多核 CPU 上的缓存直接通信。它们从不需要通过主内存来同步 CPU(除非在极少数情况下需要的数据仅在主内存中并且由于某种原因无法预取)。如果数据在一个核心的缓存中,它可以使用 MESI protocol 的变体直接进入另一个核心的缓存。 .这是一件好事——如果内核间同步必须通过 RAM,多核 CPU 的性能会非常糟糕。
关于java - 为什么 JVM 不将 "incrementing a int variable"编译为原子获取和递增操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33888761/