AQS一点点的学习

 

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;
                }
            }
        }
    }

 

 

这是AQS中的一小部分,函数功能是在队列中插入一个节点,AQS队列,为了节省开销,都是在用懒初始化的模式,在往队列里面插入的时候,才去初始化头节点和尾节点。原文注释

 

CLH queues need a dummy header node to get started. But we don't create them on construction, because it would be wasted effort if there is never contention. Instead, the node is constructed and head and tail pointers are set upon first contention. 

 

先假设只有一个线程,第一次进入到这段代码时,进入到第4行,然后正确的设置了head节点,相当于head,tail都指向一个新new出来的node节点,由于是死循环,程序会运行到第7行,运行compareAndSetTail(t, node)后,tail指向新的尾节点,就是函数传入的入参node,node的prev指针指向原来的tail,原来的tail的next指针指向node

 

private final boolean compareAndSetHead(Node update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }

 以上代码原子的设置当前对象的head字段,思想上,类似数据库的乐观锁,set head = update where head=null, 多线程模式下,只有一个线程能够设置成功,类似的向队列尾巴,添加一个节点,也只有一个线程能够成功,如果没有成功,由于调用程序写的是死循环,会向新的尾巴上增加节点,直到成功为止

private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }

 总结,这段代码很巧妙的避免了多线程问题,将一个节点加入到队列中,并用了懒初始化,头节点和尾节点

 

 

猜你喜欢

转载自clydezhou.iteye.com/blog/2385025