29

I have simple general question about AtomicReference.

Why use AtomicReference if reference assignment is atomic in java?

Also I would like to ask if reference assigment is atomic in 64-bit VMs?

Do we need volatile to have reference assigment atomic?

Michal Zmuda
  • 5,381
  • 3
  • 43
  • 39

3 Answers3

24

Why use AtomicReference if reference assignment is atomic in java?

You need it when the decision on which the creation of the new value is based can depend on the previous value of the reference. For instance when implementing some LinkedList like data structure you wan't to set the head to a new node which refers to the previous node. In the time between reading the previous node and setting head to the new one some other thread could have concurrently updated the head reference's value. If our thread would not be aware of this change, it would go lost.

Do we need volatile to have reference assigment atomic?

The operation itself would be performed atomic on the CPU core executing it but there are no guarantees that threads on other cores will be aware of it on the next read.

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
SakeSushiBig
  • 1,481
  • 2
  • 14
  • 20
  • 2
    Further more, writes to references are always atomic, taken from the JLS: Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values. – SakeSushiBig Mar 04 '13 at 16:50
  • +1. I think your answer is great, but it would be even better to demonstrate how AtomicReference class comes into play for the example you have given. – nhahtdh Mar 21 '13 at 18:54
  • Check this link: http://stackoverflow.com/questions/31042696/when-does-a-reference-need-to-be-atomic?noredirect=1&lq=1 – Ashish Pani Dec 25 '16 at 13:39
22

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

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
  • 2
    +1 that's exactly the reason for all the `Atomic...` classes. – Jim Garrison Mar 04 '13 at 07:30
  • 1
    @JimGarrison not exactly. long/float/double assignments are not atomic. It will assign the two words to the address it is assigned to in an arbitrary order (you will need to look up information about the java memory model). If you have two threads competing to write a value to that address, then you can get one word that originated in thread 1, and then the second word that originated in thread 2, resulting in a garbage value – searchengine27 Feb 18 '15 at 16:41
  • 3
    *May* be assigned in an arbitrary order. Many hardware platforms do support 64-bit word widths. And on that note, this applies only to long and double. Not float, which is 32 bits wide. – Martin Andersson Jun 29 '16 at 23:45
  • 2
    This is wrong. 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). – juancn Sep 07 '17 at 17:56
8

The reason is that even though the reference is atomic, it is atomic in a very narrow sense.

If a thread writes a non volatile reference, what is guaranteed is that other threads will see the whole write or not see it at all (no word tearing/garbage).

But at no point it is guaranteed that any other thread will ever see it nor that they will be seen in the same order.

An AtomicReference provides much stronger guarantees (besides the CAS operations), essentially they behave like volatile:

  • Any writes that happened in thread A before a volatile write are visible in thread B after a subsequent volatile read of that variable
  • volatile operations cannot be reordered
juancn
  • 2,483
  • 2
  • 20
  • 25