Search code examples
javaatomicreference

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


The source code is the same thing.

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

What's the point?


Solution

  • 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.