我已经了解到,在Java中增量int变量不是原子操作,但是,我发现CPU支持原子Fetch-and-Increment操作。
所以我的问题是,为什么JVM不将incrementing a int variable操作编译成CPU支持的原子Fetch-and-Increment操作,这在多线程编程中很有用。
早期的处理器具有原子测试集、
fetch-and-increment或交换指令,这些指令足以实现互斥,反过来可以用于实现更复杂的并发对象。 -Java并发性在实践中
发布于 2015-11-24 09:32:50
因此,我的问题是,为什么JVM不将int变量操作编译为CPU支持的原子获取和增量操作,这在多线程编程中可能很有用。
因为在典型的现代CPU上,原子读-修改-写入操作(例如增量)比它们相应的非原子操作昂贵几十倍。它不会提供任何好处--代码不能依赖于原子操作,因为它们不一定是原子的。那么,这样做有什么好处呢?
虽然它与您的问题没有直接关系,因为很多其他人都不正确地解释了这一点,但我将解释原子增量和非原子增量之间的两个区别(在硬件级别):
当然,不能保证每个CPU都是相同的,但是具有多核和流行Java实现的现代CPU几乎肯定会拥有高度优化的多核操作。当然,未来的CPU可能会更好。
另外,为了纠正另一个常见的误解:现代多核CPU上的缓存直接通信.它们从来不需要通过主内存来同步CPU(可能是在很少的情况下,所需的数据只在主内存中,并且由于某种原因无法预取)。如果数据位于一个核心的缓存中,它可以使用MESI协议的一个变体直接进入另一个核心的缓存。这是一件好事--如果内核间同步必须通过RAM,多核CPU会执行得非常糟糕。
发布于 2015-11-24 08:58:03
因为Java标准(JLS)不需要它,而且它是一个昂贵的操作,应该只在需要时使用。
发布于 2015-11-24 09:45:06
因此,我的问题是,为什么JVM不将int变量操作编译为CPU支持的原子获取和增量操作,这在多线程编程中可能很有用。
除了JVM可能需要针对缺乏此类本机指令的硬件这一显而易见的答案之外,我还想解决更普遍的问题:“为什么不让每个原始操作都是原子的,即使所有目标硬件都支持它呢?”
线程安全!=线程效率
每当您在支持它的硬件中涉及诸如fetch和add/inc这样的原子操作时,就需要一组可能要昂贵得多的指令。
有了这样的成本,想象一下使用原子获取和添加来简单地在一个巨大的循环中增加计数器,每次迭代都做非常轻的工作。这样的介绍可以大大降低循环的性能,使程序的速度减慢到原来速度的一小部分。
本质上,线程效率通常需要很大一部分代码库才能缺少线程安全性,如上面的循环计数器示例所示。理想情况下,所有只供单个线程使用的代码都应该是线程--不安全。它不应该在不需要它的地方支付锁定和同步的费用。
我们还远远没有这样的智能编译器,能够预测一个操作是否需要线程安全/原子性。因此,线程效率通常掌握在程序员手中,同时线程也是安全的。
https://stackoverflow.com/questions/33888761
复制相似问题