AtomicInteger weakCompareAndSet上的“虚假失败”是什么意思?

时间:2008-12-10 07:44:33

标签: java cas

Java AtomicInteger类有一个方法 -

boolean weakCompareAndSet(int expect,int update)

它的文件说:

  

可能会虚假地失败。

这里的'虚假失败'是什么意思?

4 个答案:

答案 0 :(得分:18)

虚假地:没有明显的理由

根据atomic包javadoc:

  

原子类还支持weakCompareAndSet方法,其适用性有限。

     

在某些平台上,弱版本可能比普通情况下的compareAndSet更有效,但不同之处在于任何给定的weakCompareAndSet方法调用都可能虚假地返回虚假(即 无明显原因 )。

     

错误返回仅表示如果需要可以重试操作,依赖于保证在变量保持expectedValue时重复调用,并且没有其他线程也尝试设置变量最终会成功。
  (例如,这种虚假失败可能是由于与预期值和当前值相等无关的内存争用效应。)

     

此外,weakCompareAndSet不提供同步控制通常需要的排序保证。


根据this thread,它不是因为“硬件/操作系统”,而是因为weakCompareAndSet使用的基础算法:

  

如果当前值==期望值,则weakCompareAndSet以原子方式将值设置为给定的更新值。可能是虚假的失败。

     

与compareAndSet()和AtomicX上的其他操作不同, weakCompareAndSet()操作不会创建任何happens-before orderings

     

因此,仅仅因为线程看到由weakCompareAndSet引起的对AtomicX的更新并不意味着它与weakCompareAndSet()之前发生的操作正确同步。

     

您可能不想使用此方法,而应该只使用compareAndSet;因为很少有情况下weakCompareAndSet比compareAndSet快,并且在许多情况下,尝试使用weakCompareAndSet而不是compareAndSet来优化代码会导致细微且难以在代码中重现同步错误。


关于 happens-before orderings 的注意事项:

  

Java内存模型(JMM)定义了读取变量的线程保证在另一个线程中看到写入结果的条件。

     

JMM定义了一个名为happen-before的程序操作的顺序。

     

发生之前 - 跨线程的排序只能通过同步公共锁或访问公共volatile变量来创建。

     

如果没有发生 - 在排序之前,Java平台有很大的自由度来延迟或改变一个线程中的写入在另一个线程中读取同一个变量的可见顺序。

答案 1 :(得分:6)

这意味着它可能会返回false(并且不会设置新值),即使它当前包含预期值。

换句话说,该方法可能无效,并且没有明显的原因返回false ... 有一些CPU体系结构可能比强CompareAndSet()具有性能优势。


关于为什么会发生这样的事情的更具体细节。

某些体系结构(如较新的ARM)使用加载链接(LL)/存储条件(SC)指令集实现CAS操作。 LL指令将值加载到内存位置并在某处“记住”该地址。如果尚未修改记住地址处的值,则SC指令将值存储到该存储器位置。硬件有可能认为该位置已经被修改,即使它显然没有多种可能的原因(原因可能因CPU架构而异):

  1. 该位置可能已使用相同的值写入
  2. 观看的地址的分辨率可能不完全是感兴趣的一个内存位置(想想缓存行)。写入“附近”的另一个位置可能会导致硬件将有问题的地址标记为“脏”
  3. 可能导致CPU丢失LL指令的已保存状态的许多其他原因 - 上下文切换,缓存刷新或页表更改可能。

答案 2 :(得分:6)

weakCompareAndSet的一个很好的用例是性能计数器 - 不需要订购,更高的更新率(因此在弱序系统上排序会受到伤害),但不会在高负载下丢弃计数(严格满足的性能计数器可能会下降99)所有计数的百分比,基本上将计数器的值相对于非竞争计数器随机地保留。)

答案 3 :(得分:0)

但是为什么允许这种情况发生呢?这是因为下面的硬件/操作系统是错误的吗?或者背后有一些很好的技术原因?