1

today I read AQS source code.I found some confuse place about AbstractQueuedSynchronizer#addWaitermethod:

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

does pred value changed after compareAndSetTail in second if statement?

so I make a test for it. but it make me more and more confuse.

I found compareAndSetTail call compareAndSwapObject finally.

so I test compareAndSwapObject in Unsafe Package.

this is my test code

    private static final long nameOffset;
    private String name="init-name";
    static Unsafe unsafe = reflectGetUnsafe();
    static {
        try {
            nameOffset = unsafe.objectFieldOffset
                    (AQSTest.class.getDeclaredField("name"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    private static Unsafe reflectGetUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            return null;
        }
    }
    @Test
    public void testUnsafe() {
        String preName = name;
        unsafe.compareAndSwapObject(this, nameOffset, preName, "new-name");
        System.out.println("preName:" + preName);
        System.out.println("name:" + name);
    }

and its output is:

preName:init-name
name:new-name

Why did name change, but preName keep the original value?

Pavel Smirnov
  • 4,611
  • 3
  • 18
  • 28
sonerila
  • 452
  • 1
  • 4
  • 7

1 Answers1

3

compareAndSwapObject() does not work the way you (probably) expect. This could be so due to slightly confusing name.

It does not actually swaps the objects. It changes only name by checking if name == preName, and if so, it just updates its value. There's always one target field to be updated, not two.

BTW, here are good unofficial docs for Unsafe class. You can get some useful information from it.

Pavel Smirnov
  • 4,611
  • 3
  • 18
  • 28
  • 1
    Hmm, the starting point was a method named `compareAndSetTail`. I can’t retrace why the OP ever came to the conclusion that it changes the `pred` argument. The method name is not suggesting that. Besides that, it’s more useful to point at the official API like `AtomicReferenceFieldUpdater` or Java 9‘s `VarHandle`, which follow the same principle, but have value for future software development. – Holger Mar 02 '20 at 11:33
  • @Holger, my guess is that the OP was confused by `compareAndSwapObject()`method thinking it swaps objects, which led him to conclusion that `compareAndSetTail()` swaps objects as well. – Pavel Smirnov Mar 02 '20 at 11:43
  • thanks, i do misunderstand `compareAndSwapObject()` params means. It do change `nameOffset`'s value after check `preName'=='nameOffset`'s value and I found `preName` obj has different **offset** with `name` through print them offset like this:```nameOffset:14 preNameOffset:16```. it lead another question [String s1==String s2(true) but FieldOffset is different](https://stackoverflow.com/questions/16859969/string-s1-string-s2-true-but-fieldoffset-is-different?rq=1) – sonerila Mar 03 '20 at 03:05