How does AbstractQueuedSynchronizer in JDK14 ensure memory visibility when using setPrevRelaxed?

Viewed 64

In method acquire, node.prev is updated by node.setPrevRelaxed(t).

It actually calls unsafe.putReference which does not ensure the visibility.

final void setPrevRelaxed(Node p) {      // for off-queue assignment
   U.putReference(this, PREV, p);
}

How dose it ensure the visibility of node.prev?

1 Answers

In Java, the happened before semantic ensure that visibility.

For example, node.setPrevRelaxed(t) is used in two place, the first one is in the enqueue method

final void enqueue(Node node) {
        if (node != null) {
            for (;;) {
                Node t = tail;
                node.setPrevRelaxed(t);        // avoid unnecessary fence
                if (t == null)                 // initialize
                    tryInitializeHead();
                else if (casTail(t, node)) {
                    t.next = node;
                    if (t.status < 0)          // wake up to clean link
                        LockSupport.unpark(node.waiter);
                    break;
                }
            }
        }
    }

node != null iff euqueue is call in Condition object which ensure this object has acquired a lock.

Another place is in acquire method

...
node.waiter = current;
                Node t = tail;
                node.setPrevRelaxed(t);         // avoid unnecessary fence
                if (t == null)
                    tryInitializeHead();
                else if (!casTail(t, node))
                    node.setPrevRelaxed(null);  // back out
                else
                    t.next = node;
...

In theses two case, the node.prev will be seen after the lock is released or casTail successfully.

Related