Небезопасный метод compareAndSwapObject механизм - PullRequest
1 голос
/ 02 марта 2020

сегодня я прочитал исходный код AQS. Я нашел какое-то запутанное место в методе AbstractQueuedSynchronizer#addWaiter:

    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;
    }

меняет ли значение pred после compareAndSetTail в секунду, если выражение?

поэтому я делаю тест на это. но это заставляет меня все больше и больше смущаться.

Я нашел compareAndSetTail звонок compareAndSwapObject наконец.

, поэтому я проверяю compareAndSwapObject в небезопасном пакете.

это мой тестовый код

    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);
    }

и его вывод:

preName:init-name
name:new-name

Почему name изменилось, но preName сохранило исходное значение?

1 Ответ

3 голосов
/ 02 марта 2020

compareAndSwapObject() не работает так, как вы (вероятно) ожидаете. Это может быть так из-за немного запутанного имени.

На самом деле не меняет объекты. Он изменяет только name, проверяя, если name == preName, и если это так, он просто обновляет свое значение. Всегда есть одно поле назначения, которое нужно обновить, а не два.

Кстати, здесь - хорошие неофициальные документы для класса Unsafe. Вы можете получить полезную информацию от него.

...