Condition源码分析

Condition

在synchronized中通过wait/notify进行线程间通信
在Lock中通过await/signal进行线程间通信
整体图如下:
在这里插入图片描述

一.分析一波condition.await源码:

 public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

1.addConditionWaiter()

首先分析addConditionWaiter():

private Node addConditionWaiter() {
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }

通过这段代码可推出构建了一个ConditionWaiter队列:
在这里插入图片描述

2. fullyRelease(node)

首先要明白锁是支持重入的

final int fullyRelease(Node node) {
        boolean failed = true;	
        try {
            int savedState = getState();	//获得state,state大于等于1
            if (release(savedState)) {    //释放锁资源
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
}

当释放后,AQS队列发生以下变化
在这里插入图片描述

3. while (!isOnSyncQueue(node))中的isOnSyncQueue(node)

  final boolean isOnSyncQueue(Node node) {
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        return findNodeFromTail(node);
}

如果waitStatus为 Node.CONDITION 说明在condition队列||node.prev==null说明node为head节点,head节点表明锁已被释放,所以 while (!isOnSyncQueue(node)) 意思是只要node不在AQS队列中就会被挂起,在condition队列挂起此时等待被唤醒。

二.分析唤醒源码

public final void signal() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }

1.doSignal(first)

private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

#① while (!transferForSignal(first) && (first = firstWaiter) != null)

final boolean transferForSignal(Node node) {
  if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))//将状态为CONDITION转换为0
      return false;
  Node p = enq(node); //p为原tail
  int ws = p.waitStatus;
  if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//将p的ws改为SIGNAL
      LockSupport.unpark(node.thread);
  return true;
}

通过transferForSignal(first)将Condition等待队列中的第一个需要唤醒的传输到AQS队列

② if ( (firstWaiter = first.nextWaiter) == null)
                lastWaiter = null;
            first.nextWaiter = null;

这里是将等待队列中的节点移除,下面就是到了刚才线程await被挂起那里的源码分析了

三.await被park那里继续分析

while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);

接上在LockSupport.park(this)被挂起了,由于唤醒了,所以继续执行,现在分析if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)进而分析checkInterruptWhileWaiting(node) node为调用await的node节点
CheckInterruptWhileWaiting代码如下:

 private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

判断线程是否被中断过,若被中断过会去判断是在await前后中断的,若在调用await之前被中断则抛出异常,否则重新中断去使得可以接下来响应;分析transferAfterCancelledWait(node):

final boolean transferAfterCancelledWait(Node node) {
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { //这里做一下说明,当一个线程处于sleep或park等阻塞状态时,interrupt可以唤醒线程,下图说明
            enq(node);
            return true;
        }
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
}

在这里插入图片描述
若上面分析的if成立,则是由于中断唤醒线程,没有正常的走流程,则表明是在唤醒前中断的,所以会抛异常。

发布了25 篇原创文章 · 获赞 30 · 访问量 1140
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章