Java volatile reference vs. AtomicReference

Viewed 45562

Is there any difference between a volatile Object reference and AtomicReference in case I would just use get() and set()-methods from AtomicReference?

6 Answers

Short answer is: No.

From the java.util.concurrent.atomic package documentation. To quote:

The memory effects for accesses and updates of atomics generally follow the rules for volatiles:

  • get has the memory effects of reading a volatile variable.
  • set has the memory effects of writing (assigning) a volatile variable.

By the way, that documentation is very good and everything is explained.


AtomicReference::lazySet is a newer (Java 6+) operation introduced that has semantics unachievable through volatile variables. See this post for more information.

No, there is not.

The additional power provided by AtomicReference is the compareAndSet() method and friends. If you do not need those methods, a volatile reference provides the same semantics as AtomicReference.set() and .get().

AtomicReference provides additional functionality which a plain volatile variable does not provide. As you have read the API Javadoc you will know this, but it also provides a lock which can be useful for some operations.

However, unless you need this additional functionality I suggest you use a plain volatile field.

Sometimes even if you only use gets and sets, AtomicReference might be a good choice:

Example with volatile:

private volatile Status status;
...
public setNewStatus(Status newStatus){
  status = newStatus;
}

public void doSomethingConditionally() {
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
  }
}

The implementation with AtomicReference would give you a copy-on-write synchronization for free.

private AtomicReference<Status> statusWrapper;
...

public void doSomethingConditionally() {
  Status status = statusWrapper.get();
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
  }
}

One might say that you could still could have a proper copy if you substituted:

Status status = statusWrapper.get();

with:

Status statusCopy = status;

However the second one is more likely to be removed by someone accidentally in the future during "code cleaning".

Related