AtomicReference中的compareAndSet和weakCompareAndSet有什么区别?

2022-09-02 09:37:51

源代码是一回事。

public final boolean compareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

public final boolean weakCompareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

有什么意义?


答案 1

在 x86 上,LOCK CMPXCHG 指令用于实现 CAS。它是原子的,提供(接近)最大排序保证,并且不会遭受虚假故障。因此,在 x86 平台上,保证较少的 CAS 没有任何好处。

但在其他平台上,如PowerPC或ARM(没有LSE扩展),CAS是作为几个指令的序列实现的,这些指令提供LL / SC行为和内存屏障作为单独的构建块。这为 CAS 在订购和故障保证方面的强大程度创造了一些回旋余地。相反,这意味着全强度 CAS 可能比某些并发算法所需的指令序列更昂贵。

许多并发算法涉及在 CAS 失败时重试或重新计算操作,然后重试的循环。由于LL / SC可能会虚假地失败,因此基于它的强大CAS实现必须在内部循环。如果代码已经包含一个外部循环,它可以通过将强 CAS 替换为允许虚假失败的弱 CAS 来避免内部循环。

因此,weakCAS的存在是为了允许在弱序架构上执行更有效的代码。

javadoc对弱化排序的确切含义含糊不清,因为它目前无法用java内存模型来表示。将来可能会对其进行修订,因为它将与C++11内存模型更紧密地保持一致。

JSR-133 说明书的多处理器一章中的表概述了平台的不同之处。


答案 2

javadoc是这样解释的:weakCompareAndSet

如果当前值 == 预期值,则以原子方式将值设置为给定的更新值。

可能会虚假地失败,并且不提供排序保证,因此很少是比较AndSet的合适替代方案。

简而言之,javadoc是说该版本是(或曾经是)提供“较弱”保证的版本。weak

现在,正如您所观察到的,这两种方法的当前实现是相同的。从Java 6到Java 8(至少)都是如此,基于Grepcode站点上的源代码。

因此,我推测这两种方法的实现是:

  • 原本不同,但作为实施大修的结果而变得相同:Unsafe

    • 为了权宜之计(例如,为了节省实施工作
    • 因为“弱”版本的假定性能,或者
    • 因为“弱”版本是有问题的;例如,它太难正确使用。
  • 最初是相同的,并且指定了差异(但未实现),因为设计人员认为可能存在性能优势。

最后一种解释不太可能。如果两个方法最初实现相同,则将它们重新实现为不同的方法可能会破坏预先存在的代码。这是一个坏主意,即使对于.Unsafe


@assylias / @ Stefan Gobel评论了另一种解释。基本上,我们在源代码中看到的“相同代码”实际上可能被JIT编译器重写,为这两种方法提供不同的机器代码。

这当然是合理的。JIT 编译器确实为某些(非本机)方法调用生成了特殊情况的代码:所谓的“内部函数”。


在 Java 9 中,该方法被标记为已弃用。源代码中的解释是:weakCompareAndSet

此方法具有明显的记忆效应,但方法名称暗示了易失性记忆效应(请参阅 {@link #compareAndExchange} 和 {@link #compareAndSet} 等方法)。为了避免混淆简单或易失性的记忆效应,建议改用方法 {@link #weakCompareAndSetPlain}。

另一方面,我们现在看到它现在的实现方式与 / 不同:compareAndSetweakCompareAndSetweakCompareAndSetPlain

public final boolean compareAndSet(V expectedValue, V newValue) {
    return VALUE.compareAndSet(this, expectedValue, newValue);
}

public final boolean weakCompareAndSet(V expectedValue, V newValue) {
    return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
}

其中 声明为 .上面使用的方法被标记为固有的候选者。VALUEjava.lang.invoke.VarHandleVarHandlenative


推荐