Как указывает Дуг Ли в [The java.util.concurrent Framework Synchronizer Framework] [1] http://gee.cs.oswego.edu/dl/papers/aqs.pdf, что
Но потому что не существует применимых методов для атомарной блокировки без блокировкивставка узлов двойного связанного списка с использованием compareAndSet, эта ссылка не является атомарно установленной как часть вставки;он просто назначается.
pred.next = узел;
после вставки.Это отражено во всех обычаях.Следующая ссылка обрабатывается только как оптимизированный путь.Если преемник узла, по-видимому, не существует (или, по-видимому, отменяется) через его следующее поле, всегда можно начать с конца списка и пройти назад, используя поле pred, чтобы точно проверить, действительно ли он существует.
фрагмент кода добавления узла для синхронизации очереди, скопированный из формы Исходный код AbstractQueuedSynchronizer:
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
мой вопрос в исходном коде - поле next класса Node является энергозависимым объектом, если compareAndSetTail success, то следующее поле t не должно быть нулевым, поэтому может возникнуть ситуация null .фрагмент кода:
static final class Node {
//....ignored
volatile Node next;
volatile Node prev;
//.... ignored
}
Кроме того, я не совсем понимаю hasQueuedPredecessors .Если h! = T, то следующее поле h не должно быть нулевым, почему h.next == null также означает hasQueuedPredecessors?
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}