When to Use Atomicreference in Java

When to use AtomicReference in Java?

Atomic reference should be used in a setting where you need to do simple atomic (i.e. thread-safe, non-trivial) operations on a reference, for which monitor-based synchronization is not appropriate. Suppose you want to set a specific field only if the state of the object has changed during processing:

AtomicReference<Object> cache = new AtomicReference<Object>();

Object cachedValue = new Object();
cache.set(cachedValue);

//... time passes ...
Object cachedValueToUpdate = cache.get();
//... do some work to transform cachedValueToUpdate into a new version
Object newValue = someFunctionOfOld(cachedValueToUpdate);
boolean success = cache.compareAndSet(cachedValue,cachedValueToUpdate);

Because of the atomic reference semantics, you can do this even if the cache object is shared amongst threads, without using synchronized. In general, you're better off using synchronizers or the java.util.concurrent framework rather than bare Atomic* unless you know what you're doing.

Two excellent dead-tree references which will introduce you to this topic:

  • Herlihy's excellent Art of Multiprocessor Programming
  • Java Concurrency in Practice

Note that (I don't know if this has always been true) reference assignment (i.e. =) is itself atomic (updating primitive 64-bit types like long or double may not be atomic; but updating a reference is always atomic, even if it's 64 bit) without explicitly using an Atomic*.

See the Java Language Specification 3ed, Section 17.7.

When to use AtomicReference (Java)? Is it really necessary?

It's a reference, so that's what is compared. The documentation makes it very clear that it's an identity comparison, even using the == operation in its description.

I use AtomicReference and other atomic classes very frequently. Profiling shows that they perform better than the equivalent methods using synchronization. For example, a get() operation on an AtomicReference requires only a fetch from main memory, while an a similar operation using synchronized must first flush any values cached by threads to main memory and then perform its fetch.

The AtomicXXX classes provide access to native support for compare-and-swap (CAS) operations. If the underlying system supports it, CAS will be faster than any scheme cooked up with synchronized blocks in pure Java.

What is an idiomatic way to use AtomicReference while using a Map in vavr?

Is my understanding correct?

Well the understanding is correct, the code is a little bit off. You don't need to reassign this.allAgents (actually that's the whole point) - just the updateAndGet is enough, it operates on the same variable.

...should always use an AtomicReference instead of just the Reference to that member variable...

AtomicReference is just one of the ways, you can use locks, synchronization or other mechanisms. If performance really matters to you then you should consider other options - if you have really high contention (threads often fight for this variable) then locks will perform better than atomics. As far as patterns go, I would suggest a pattern of having your fields final - you are gonna avoid mistakes like that (overwriting a vavr list variable for example) thanks to final fields.

then do we really get any benefit of immutable collections offered by Vavr?

You do benefit, it's a completely different thing, and it's really amazing actually. I'm bad at explaining, but let's go.

Imagine you have a table (your CourierSlottingMachine class) and there is a box (your Map) on that table. The box is protected by a guard (AtomicReference), so only one person can come and do something with it. The box itself is designed in a way that only one person can operate on it.

So do you really need a guard if the box is already protected? No. So in your case you basically do not benefit, could just use ConcurrentHashMap.

But now imagine that you let people take the box with them, wherever they want (returning the Map from your method). If one person takes your box, then he has his own copy, he can do whatever he wants with it - destroy it, cut it in half and make two boxes, whatever. Then the best part - if he wants the same box he had a couple minutes ago, he just comes in and takes it again. And other people can take it aswell and do whatever they want, and it's not gonna affect other peoples boxes. Why a guard then? Imagine you added something valuable to the box and you want your box to be on display right now - that's what the guard is for.

Now imagine a same case if the box wouldn't be a vavr box - it could but a normal java box, or even a concurrent java box. There is always only one box. People can take it, but they have to return it before anyone else is allowed to take it. No private boxes anymore, no copies, no safe point of return - someone else may even steal your items you put there before.

This analogy fell through halfway, but I hope it helps at least a little bit :)

Which is the difference between AtomicReference and Synchronized?

You didn't initialize the reference in the first example, it should probably be:

public class Internet {
AtomicReference<String> address = new AtomicReference<String>();
public String getAddress(){
String s = address.get();
return s == null ? null : s.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}

Where the access restriction is located is important. If you put the control within the object being accessed then it can have sole control of its invariants, which is much less fragile than relying on the threads to all synchronize properly, where one badly behaved accessing thread can corrupt the thing being accessed. So the first example is much better on that account.

If you change the second example so that the object has control over its own locking (so it is not relying on threads accessing it to do so safely), like this:

public class Internet {
private final Object lock = new Object();
private String s;
public String getAddress() {
synchronized(lock) {
return s;
}
}
public void setAddress(String s) {
synchronized(lock) {
this.s = s;
}
}
}

then it's a closer comparison, one relies on locking and the other on atomic references. The one using AtomicReference tries to avoid locking using machine-level atomic processing instructions. Which is faster may depend on your hardware and jvm and the processing load, typically the atomic approach should be faster. The synchronized approach is a more general purpose mechanism; with the synchronized block you can group together multiple assignments much more easily, where with atomic references it's much more involved.

As James says in his answer, with synchronization your threads are waiting for a lock; there is no timeout, and deadlock is possible. With the atomic reference the thread makes its change with no waiting on a shared lock.

The simplest and best-performing way to implement this would be to organize your code so that you can make the object immutable, so you would avoid all locking, busy-waiting, and cache updating:

public final class Internet {
private final String s;
public Internet(String s) {
this.s = s;
}
public String getAddress() {return s;}
}

In descending order of preference:

  • Prefer immutability whenever possible.
  • For code that can't be immutable, try to confine mutation to a thread.
  • If only one thing has to change across threads, use the atomic approach.
  • If multiple changes across threads need to occur together undisturbed by other threads, use locking.

is java AtomicReference thread safe when used within parallelStream?

You are invoking LongAccumulator.intValue() which is documented as:

Returns the current value as an int after a narrowing primitive conversion.

and following the linke to the get() method we will learn:

Returns the current value. The returned value is NOT an atomic snapshot; invocation in the absence of concurrent updates returns an accurate result, but concurrent updates that occur while the value is being calculated might not be incorporated.

So while the AtomicReference.updateAndGet operation is thread safe, your concurrent invocation of LongAccumulator.intValue() and LongAccumulator.accumulate is not. A LongAccumulator is intended for performing concurrent accumulate operations, followed by fetching the result after all accumulate operations have been finished. Note that even if get() was returning a correct snapshot, the fact that the invocation of intValue() and the subsequent accumulate() are two distinct, hence non-atomic, operations made the operation still prone to data races.

In most cases, if you find yourself trying to manipulate data structures in a forEach, you are using the wrong tool for the job, making the code unnecessarily complicated and error prone.
As Clayn hinted in a comment, a
words.parallelStream().max(Comparator.comparingInt(String::l‌​ength)) will do the job concisely and correct.

Reference assignment is atomic so why use AtomicReference

My previous answer was incorrect, as explained in the comment by juancn:

That's the difference between Atomic* classes and volatile access. Reference assignment is atomic only in the sense that no word tearing can occur, but there's no visibility or reordering guarantees. Java guarantees atomic writes in this restricted sense for all primitive types and references but not for long/double (although in 64bit VMs I think they're always atomic).

Previous answer

It is necessary, mainly for compareAndSet and getAndSet methods. You cannot do this atomically otherwise (2 operations are needed).

What is a usecase for Java AtomicReference#getAndSet?

No, these are not equivalent. The difference is that getAndSet does both operations atomically, not just an atomic get and then an atomic set.

getAndSet is always guaranteed to return exactly the value that was stored in the reference right before the new value was set. The volatile version might "skip" values inserted by other threads.



Related Topics



Leave a reply



Submit