关于共享锁中doReleaseShared()理解

关于共享锁中doReleaseShared()理解

public final boolean releaseShared(int arg) {
	//同一时刻只允许一个线程进入doReleaseShared()方法
	if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

理想情况下唤醒这个节点后面所有的线程。

private void doReleaseShared() {
    for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            //这里说明了头节点后面是有节点的,需要被唤醒。
            if (ws == Node.SIGNAL) {
         		//这里更新失败,是因为会出现并发情况,因为刚唤醒的线程也会调用doReleaseShared()所以此时是有多个线程同时执行这个方法。
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                unparkSuccessor(h);
            }
            //head.waitStatus=0的情况有两种
            //1、就是head节点没有及时更新,线程被唤醒之后获取到了锁,在更新head之前,又经过一轮循环执行到这。  但是如果节点没有及时更新就会退出。所以执行到这一步只可能是情况2
            //2、head节点及时更新了,但是到了最后一个节点,它的head.waitStatus=0
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        //节点没有及时更新,就退出。
        if (h == head)                   // loop if head changed
            break;
    }
}

所以说整体的逻辑就是在head能及时更新的情况下,唤醒队列中所有的节点,直到队列中只有head。
并将这个head设置为compareAndSetWaitStatus(h, 0, Node.PROPAGATE)
然后通过下面代码退出。

if (h == head)                   // loop if head changed
     break;

那什么时候compareAndSetWaitStatus(h, 0, Node.PROPAGATE)修改会失败呢?
就是当ws==0判断后面的一瞬间又有新的节点加入然后将head的值又改为-1,然后执行continue又会将刚加入的节点给唤醒。

else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
      continue;      

所以以上代码是尽可能的将所有的节点给唤醒,而唤醒的线程又会帮助去唤醒线程,包括新加入的节点。


版权声明:本文为qq502130297原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。