Search code examples
javaconcurrencyjvmunsafe

Unsafe's method compareAndSwapObject mechanism


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?


Solution

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