почему java AbstractQueuedSynchronizer следующая ссылка атомарно не установлена ​​как часть вставки - PullRequest
0 голосов
/ 12 сентября 2018

Как указывает Дуг Ли в [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());
}
...