4

In one of my programs, I was trying to update the value of an Atomic Integer, but could not decide between set() and getAndSet() methods because they both seem to do the same. I have already gone through this and this post, but they are comparing set and compareAndSet(which gives up setting the provided value, if the thread doesn't have the expected value) whereas I am interested to compare set with getAndSet(which returns only after setting the provided value).

 //Sets the newValue to the volatile member value public final void set(int newValue) { value = newValue; } 

and

 public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } //Doesn't give up until it sets the updated value. So eventually overwrites the latest value. public final int getAndSetInt(Object paramObject, long paramLong, int paramInt) { int i; do { i = getIntVolatile(paramObject, paramLong); } while (!compareAndSwapInt(paramObject, paramLong, i, paramInt)); return i; } 

I am not able to find out any major difference between the two methods.

  1. Why have set() when we have getAndSet(). One may choose to not use the value returned by getAndSet().

  2. When should one use each of these methods?

0

2 Answers 2

1

According to the java documentation, they both do different things:

AtomicReference#getAndSet will set the internal value to whatever you pass in, but will return the old value.

AtomicReference<Integer> reference = new AtomicReference<>(10); int value = reference.getAndSet(14); System.out.println(value); // prints 10 

AtomicReference#set will set the internal value, and that's it. It returns void.

AtomicReference<Integer> reference = new AtomicReference<>(10); reference.set(15); System.out.println(reference.get()); // prints 15; 
Sign up to request clarification or add additional context in comments.

4 Comments

So, why have set() when we have getAndSet(). One may choose to not use the value returned by getAndSet().
Cases can differ. For some, it's more time consuming to write int last = reference.get(); doSomethingWithLastReference(last); reference.set(15);. It makes more sense to be able to do it in one go (and reduces the amount you need to type).
Note that invoking 'get' then invoking 'set' is not equivalent to invoking 'getAndSet': 'getAndSet' is atomic. One is guaranteed to obtain the value mostly recently assigned to the atomic variable with 'getAndSet'. That guarantee does not exist when making two invocations.
Whether to use 'set' or 'getAndSet' depends on intent and style. In many cases, 'set' (or 'getAndSet') simply more clearly expresses what the program is to do. But, if you are trying to avoid destructive operations, then you would use 'getAndSet', and would then likely wrap that in an explicit destructive operation: 'explicitDestroy( atomicVar.getAndSet( newValue ) )'. Note that if you turn compiler warning up very high, you will get a warning if you use 'getAndSet' and do nothing with the return value.
0

A pure store is much more efficient than an atomic RMW, so it makes sense to provide an API for the cheaper operation. Use .set() whenever you don't need the old value.

On x86, this pure-store only cheaper if you can use a memory_order weaker than seq_cst, otherwise the pure store will use xchg, which is a getAndSet, because that will also drain the store buffer. (Or mov + a full barrier which is just as expensive.) So Java on x86 might not get any benefit from plain set.

But at least on AArch64, a seq_cst pure store only has special ordering wrt. seq_cst loads: stlr can't reorder with a later ldar from the same thread, but can reorder with other later loads and stores so it doesn't have to wait for the store buffer to drain before letting later memory ops run.

I wouldn't expect a JVM to optimize getAndSet() with an unused return value into just a set().

Such an optimization might not even be correct on PowerPC, although it would be on other mainstream ISAs I think, like x86 and AArch64 which are multi-copy atomic (no IRIW reordering). In C++ terms, a pure store doesn't continue a release-sequence, but an RMW like getAndSet (exchange) does, because at least one ISA doesn't quite always guarantee synchronization with threads that wrote previous values in the modification-order. What does "release sequence" mean?

Of course, if Java still doesn't allow memory orders weaker than sequential consistency (at least not with this API), that's also irrelevant.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.