what's the difference between compareAndSet and weakCompareAndSet in AtomicReference?

On x86 the LOCK CMPXCHG instruction is used to implement CAS. It is atomic, provides (near-)maximal ordering guarantees and does not suffer from spurious failures. So on x86 platforms there is nothing to gain from a CAS with fewer guarantees.

But on other platforms such as PowerPC or ARM CAS is implemented as a sequence of several instructions which provide LL/SC behavior and memory barriers as separate building blocks. This creates some wiggle room how strong your CAS can be both in terms of ordering and failure guarantees. Conversely it means a full-strength CAS can be more costly instruction sequence than required by some concurrent algorithms.

Many concurrent algorithms involve loops that retry or recompute an operation when a CAS fails and then try again. Since LL/SC can fail spuriously a strong CAS implementation based on it has to loop internally. If the code already contains an outer loop it can avoid the inner loop by replacing the strong CAS with a weak CAS that is allowed to fail spuriously.

So weakCAS exists to allow more efficient code on weakly ordered architectures.

The javadoc is vague about what exactly the weakened ordering means because it currently cannot be expressed in terms of the java memory model. That may be revised in the future when it will be more closely aligned with the C++11 memory model.

The table in the Multiprocessor chapter of the JSR-133 Cookbook provides an overview how platforms differ.


The weakCompareAndSet javadoc explains it thus:

Atomically sets the value to the given updated value if the current value == the expected value.

May fail spuriously and does not provide ordering guarantees, so is only rarely an appropriate alternative to compareAndSet.

In short the javadoc is saying that the weak version is (or was) a version that provided "weaker" guarantees.

Now, as you observe, the current implementations for these two methods are identical. This is true from Java 6 through Java 8 (at least), based on the source code on the Grepcode site.

So I surmise that the implementations of these two methods were either:

  • originally different, but made the same as a result of an overhaul of the implementation of Unsafe:

    • for expediency (e.g. to save implementation effort
    • because the supposed performance of the "weak" version, or
    • because the "weak" version was problematic; e.g. it was too hard to use correctly.
  • originally the same, and the difference was specified (but not implemented) because the designers thought there might be performance advantages.

The last explanation is unlikely. If two methods are initially implemented the same, reimplementing them as different would risk breaking preexisting code. That is a bad idea, even for Unsafe.


@assylias / @ Stefan Gobel commented an alternative explanation. Basically, the "identical code" that we see in the source code may actually be rewritten by the JIT compiler to give different machine code for the two methods.

This is certainly plausible. The JIT compiler does have special case code generation for some (non-native) method calls: the so-called "intrinsics".


In Java 9, the weakCompareAndSet method was marked as Deprecated. The explanation in the source code is:

This method has plain memory effects but the method name implies volatile memory effects (see methods such as {@link #compareAndExchange} and {@link #compareAndSet}). To avoid confusion over plain or volatile memory effects it is recommended that the method {@link #weakCompareAndSetPlain} be used instead.

On the flipside, we now see that compareAndSet is now implemented differently to weakCompareAndSet / weakCompareAndSetPlain:

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);
}

where VALUE is declared as a java.lang.invoke.VarHandle. The VarHandle methods used above are native and marked as intrinsic candidates.