сегодня я прочитал исходный код 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
сохранило исходное значение?