鍍金池/ 問(wèn)答/Java  Linux  網(wǎng)絡(luò)安全/ 非阻塞鏈表 一行代碼不理解

非阻塞鏈表 一行代碼不理解

使用cas操作實(shí)現(xiàn)非阻塞鏈表 其中put方法 代碼如下

public class LinkedQueue <E> {
    private static class Node <E> {
        final E item;
        final AtomicReference<Node<E>> next;
        Node(E item, Node<E> next) {
            this.item = item;
            this.next = new AtomicReference<Node<E>>(next);
        }
    }
    private AtomicReference<Node<E>> head
        = new AtomicReference<Node<E>>(new Node<E>(null, null));
    private AtomicReference<Node<E>> tail = head;
    public boolean put(E item) {
        Node<E> newNode = new Node<E>(item, null);
        while (true) {
            Node<E> curTail = tail.get();//1
            Node<E> residue = curTail.next.get();
            if (curTail == tail.get()) {//2
                if (residue == null) /* A */ {
                    if (curTail.next.compareAndSet(null, newNode)) /* C */ {
                        tail.compareAndSet(curTail, newNode) /* D */ ;
                        return true;
                    }
                } else {
                    tail.compareAndSet(curTail, residue) /* B */;
                }
            }
        }
    }
}

代碼來(lái)源: developerworks文章《非阻塞算法簡(jiǎn)介》 非阻塞鏈表 章節(jié)

疑惑:這段代碼的大體思路、原理 是理解的,但2處注釋的代碼,即if (curTail == tail.get())這行的判斷不理解。這個(gè)判斷是有必要的嗎?可以去掉嗎?為什么?

2處的curTail就是1處tail.get() 的結(jié)果。如果需要判斷的話,應(yīng)該是在并發(fā)情況下,1、2處分別調(diào)用tail.get()的返回的可能不是同一個(gè)對(duì)象。也就是說(shuō),2處判斷的時(shí)候,tail可能被修改了。1到2處之間沒(méi)有修改tail的動(dòng)作,所以只能是別的一個(gè)線程修改了tail;只看這段代碼的話,只能是別的線程調(diào)用put方法時(shí)執(zhí)行了B或D。所以安插了這么一個(gè)判斷。

但是有什么用呢?這是個(gè)“先判斷后執(zhí)行”的動(dòng)作,但是因?yàn)榉亲枞患渔i,[判斷+執(zhí)行]并沒(méi)有被同步起來(lái);所以,可能剛剛判斷之后,tail就被改掉,判斷就會(huì)失效。所以看起來(lái)這個(gè)判斷是完全可以去掉的。是為了性能,判斷失敗后 可以少走一次循環(huán)體嗎?

回答
編輯回答
笑浮塵

留個(gè)坑,坐看大神回答

2018年5月11日 10:46