Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AtomicReference vs AtomicReferenceFieldUpdater, what's a purpose of AtomicReferenceFieldUpdater?

I'd like to atomically upgrade my reference. For example to use compareAndSet, getAndSet and other atomic operations.

I came from C++, so in C++ I've got volatile keyword and different atomic intrinsics, or the <atomic> API. In java, there's also a volatile keyword and different unsafe atomic operations.

By the way, there's also a well-documented AtomicReference (as well as Long, Integer, Boolean), so JDK creators provided us a way to safely execute atomic operations against references and primitives. There's nothing wrong about the API, it is rich and seems very familiar.

But, there's also an AtomicReferenceFieldUpdater whick provides a kinda weird way to execute atomic operations: you have to "find" the field via reflection by name and then you can use exactly the same operations.

So my questions are:

  1. What's the purpose of AtomicReferenceFieldUpdater at all? In my opinion it is implicit and kinda weird: you need to declare a volatile variable filed AND and the field updater itself. So where should I use a FieldUpdater?
  2. It provides an indirection: you're manipulating (not changing!) the FieldUpdater, not the variable, this confuses.
  3. Performance: as far as I know, both AtomicReferenceFieldUpdater and AtomicReference are delegating to the Unsafe, so their performance is similar, but anyway: are there any performance penalties of FieldUpdater agaist Reference?
like image 676
Netherwire Avatar asked Oct 07 '18 09:10

Netherwire


1 Answers

It's used to save memory.

Example from the doc:

class Node {
   private volatile Node left, right;

   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");

   Node getLeft() { return left; }
   boolean compareAndSetLeft(Node expect, Node update) {
     return leftUpdater.compareAndSet(this, expect, update);
   }
   // ... and so on
 }

it declares left and right as Node directly. And the AtomicReferenceFieldUpdater is static final.

Without AtomicReferenceFieldUpdater, you might need declare them as AtomicReference<Node>.

private  AtomicReference<Node> left, right;

which consumes more memory than Node. When there are many instances of Node, it consumes much more memory than first approach.

like image 59
xingbin Avatar answered Nov 08 '22 17:11

xingbin