Java Параллелизм на практике "Листинг 15.7. Вставка в алгоритм неблокирующей очереди Майкла-Скотта (Michael and Scott, 1996)." - PullRequest
2 голосов
/ 22 января 2020

Я читаю Java Параллелизм на практике и встречаю 15.7 Вставка в алгоритм неблокирующей очереди Майкла-Скотта. .

package net.jcip.examples;

import java.util.concurrent.atomic.*;

import net.jcip.annotations.*;

/**
 * LinkedQueue
 * <p/>
 * Insertion in the Michael-Scott nonblocking queue algorithm
 *
 * @author Brian Goetz and Tim Peierls
 */
@ThreadSafe
public class LinkedQueue <E> {

    private static class Node <E> {
        final E item;
        final AtomicReference<LinkedQueue.Node<E>> next;

        public Node(E item, LinkedQueue.Node<E> next) {
            this.item = item;
            this.next = new AtomicReference<LinkedQueue.Node<E>>(next);
        }
    }

    private final LinkedQueue.Node<E> dummy = new LinkedQueue.Node<E>(null, null);
    private final AtomicReference<LinkedQueue.Node<E>> head
            = new AtomicReference<LinkedQueue.Node<E>>(dummy);
    private final AtomicReference<LinkedQueue.Node<E>> tail
            = new AtomicReference<LinkedQueue.Node<E>>(dummy);

    public boolean put(E item) {
        LinkedQueue.Node<E> newNode = new LinkedQueue.Node<E>(item, null);
        while (true) {
            LinkedQueue.Node<E> curTail = tail.get();
            LinkedQueue.Node<E> tailNext = curTail.next.get();
            if (curTail == tail.get()) { // what is the purpose of this check?
                if (tailNext != null) {
                    // Queue in intermediate state, advance tail
                    tail.compareAndSet(curTail, tailNext);
                } else {
                    // In quiescent state, try inserting new node
                    if (curTail.next.compareAndSet(null, newNode)) {
                        // Insertion succeeded, try advancing tail
                        tail.compareAndSet(curTail, newNode);
                        return true;
                    }
                }
            }
        }
    }
}

Если у нас есть if (curTail == tail.get()) проверьте, мы можем узнать, был ли tail изменен после LinkedQueue.Node<E> curTail = tail.get();, если tail был изменен, выполните while l oop снова. Но если мы пропустим эту проверку и tail был изменен после LinkedQueue.Node<E> curTail = tail.get();, мы потерпим неудачу в tail.compareAndSet(curTail, tailNext); или curTail.next.compareAndSet(null, newNode), мы снова выполним while l oop, , поэтому результат будет так же, как наличие чека .

Итак, есть ли другие различия между наличием или отсутствием этого чека? Можем ли мы просто опустить этот чек?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...