Difference between getAndSet and compareAndSet in AtomicBoolean
Asked Answered
T

4

23

The thread title should be self-explnatory... I'm a bit confused between the specification of below methos from AtomicBoolean class:

  • java.util.concurrent.atomic.AtomicBoolean#compareAndSet
  • java.util.concurrent.atomic.AtomicBoolean#getAndSet

My assemption is that both would result in the same behavior when used as a boolean clause in an if condition:

public class Test {
  private AtomicBoolean flag = AtomicBoolean(false);

  public void processSomeAction() {
    if (flag.getAndSet(false)) { // Shouldn't this be similar to flag.compareAndSet(false)
      // process some action
    }
  }
  //...
  private void internalMutatorMethod() {
    // do some staff then update the atomic flag
    flas.set(true);
  }
}

Assuming that I want to retrieve the current flag value and update it automaticlly, shouldn't both methods produce the same behavior?

I would much appreciate any explanations regarding how and when to use each of those if I'm missing internal differences.

Thao answered 26/1, 2015 at 9:40 Comment(1)
compareAndSet has two argument. The javadoc indicates that it is completely different from getAndSet. - You can write a call for compareAndSet that does the same as getAndSet, but that's hardly worth a question.Cullet
U
26

The documentation is pretty clear.

  • getAndSet --> "Atomically sets to the given value and returns the previous value."
  • compareAndSet --> "Atomically sets the value to the given updated value if the current value == the expected value."

Not surprisingly, compareAndSet takes two arguments.

In your specific case:

  • if (flag.getAndSet(false)) will set flag to false only if its previous value was true
  • That would be the equivalent of if (flag.compareAndSet(true, false))
Unifilar answered 26/1, 2015 at 9:44 Comment(4)
Yes, the documentation is pretty clear as you suggested and I can see the difference generally speaking... but I'm seeking to see difference based on the code snippet I wrote in the main thread. Does it make any difference in there?Thao
That was exactelly what I was looking forward to confirm... They should be equivalent in my case :)Thao
@Thao You are incorrrectly assuming compareAndSet takes in only one arg.Nugatory
"if (flag.getAndSet(false)) will set flag to false only if its previous value was true" - this is not correct. getAndSet(<val>) always sets the value to <val> whether the previous value was true or false.Mellen
H
11

You can look at the code for better understanding :

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

In getAndSet, if the value of the boolean has changed between the time you get() the old value and the time you try to change its value, compareAndSet won't change its value. Therefore, getAndSet calls compareAndSet in a loop until the boolean is set to the new value.

As to your code example :

flag.getAndSet(false) returns the old value of the AtomicBoolean. On the other hand, flag.compareAndSet(x,false) (note there are two arguments) returns whether the AtomicBoolean was modified, or in other words, it returns whether the old value of the AtomicBoolean was x.

Hardly answered 26/1, 2015 at 9:47 Comment(0)
E
1

When I have checked the implementation I found following

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

Also when checking the javadoc, compareAndSet sets value only if the comparison pass while getAndSet simply set the value and return the previous value.

Emerick answered 26/1, 2015 at 9:46 Comment(1)
That is only true in earlier versions of the JDK. JDK 8 rewrote it as a do-while loop, and JDK 9 through JDK 14 use a VarHandle implementation, which is native.Chevalier
F
0

The thread is a bit old but nobody mentioned that getAndSet will be more efficient than compareAndSet. CAS is a very costly instruction (on all CPU architectures, so JVM does not matter here). So they are not really equivalent.

So regarding the OP, both methods produce the same behaviour but it will not have the same performance, use getAndSet when you can.

Foetation answered 7/11, 2018 at 15:25 Comment(2)
Apparently that's not true, particularly if talking about lock cmpxchg: #5340269. Further, that instruction in itself is not super costly compared with the effect it has on other cores: potentially forcing them to go read from main memory again.Galoot
Can you pinpoint to the relevant part? They're both slow instruction, because of the memory lock indeed. But (lock) xchg still wins on recent Intel archs at least (agner.org/optimize/instruction_tables.pdf). cmpxchg is slower because it's more complex by definition and needs more µops.Foetation

© 2022 - 2024 — McMap. All rights reserved.