FutureTask WaitNode 源码分析

阅读更多
waiter 存放等待的线程,这是一个单链表,没有用 lock 或者 sync 但是实现了线程安全.

static final class WaitNode {
        // 记录当前线程.
        volatile Thread thread;
        // 指向下一个线程.
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

这里为啥会使用 volatile 进行修饰了,而 Treober Stack 中则没有使用 volatile 进行修饰?

我们先看下 Treober Stack:

private static class Node {
        public final E item;
        public Node next;
        public Node(E item) {
            this.item = item;
        }
    }


为什么了?

我觉得在于 removeWaiter 的实现:


private void removeWaiter(WaitNode node) {
        if (node != null) {
            // 设置节点的线程为空,做删除标记
            node.thread = null;
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    // thread不为空,continue
                    if (q.thread != null)
                        pred = q;
                    // thread 为空且 pred 不为空
                    else if (pred != null) {
                        // 删除 q
                        pred.next = s;
                        // 检查一下 pred 的 thread,如果被其他线程修改,retry outer loop
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    // thread 为空且 pred 为空说明 q 为栈顶,将 q.next设置为栈顶,失败则 retry.
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
    }

这里面使用到了 node.thread = null 和 if(q.thread != null)

在多线程的环境中,如果不使用 volatile 进行修饰的话,一个线程将将 node.thread 赋值为了 null,但是其他线程发现不了这个操作导致发生错误.

你可能感兴趣的:(FutureTask,多线程,WaitNode)