深入理解AQS--jdk层面管程实现【管程详解的补充】( 二 )

Condition接口详解1.代码展示
//Condition用来替代synchronized锁的监视器的功能,而且更加灵活//一个Condition实例需要与一个lock进行绑定public interface Condition {//调用此方法的线程将加入等待队列,阻塞直到被通知或者线程中断void await() throws InterruptedException;//调用此方法的线程将加入等待队列,阻塞直到被通知(线程中断忽略)void awaitUninterruptibly();//调用此方法的线程将加入等待队列,阻塞直到被通知或者线程中断或等待超时long awaitNanos(long nanosTimeout) throws InterruptedException;//调用此方法的线程将加入等待队列 , 阻塞直到被通知或者线程中断或等待超时boolean await(long time, TimeUnit unit) throws InterruptedException;//调用此方法的线程将加入等待队列,阻塞直到被通知或者线程中断或超出指定日期boolean awaitUntil(Date deadline) throws InterruptedException;//唤醒一个等待中的线程void signal();//唤醒所以等待中的线程void signalAll();}2.发现说明
【1】在Condition中,用await()替换wait() , 用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式 , Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法 。Condition的强大之处在于,对于一个锁,我们可以为多个线程间建立不同的Condition 。如果采用Object类中的wait(), notify(), notifyAll()实现的话,当写入数据之后需要唤醒读线程时,不可能通过notify()或notifyAll()明确的指定唤醒读线程,而只能通过notifyAll唤醒所有线程,但是notifyAll无法区分唤醒的线程是读线程,还是写线程 。所以,通过Condition能够更加精细的控制多线程的休眠与唤醒 。
【2】但,condition的使用必须依赖于lock对象,通过lock对象的newCondition()方法初始化一个condition对象 。
ConditionObject类详解【Condition接口的实现类】1.属性值解析
//由头尾两个节点指针形成的链表来达到队列的效果private transient Node firstWaiter;private transient Node lastWaiter;2.方法解析
【1】核心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 cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}//addConditionWaiter将一个节点添加到condition队列中 。在入队时,判断当前尾节点是不是CONDITION 。如果不是则判断当前尾节点已经被取消,将当前节点出队 。那么也就是说在队列中的节点状态,要么是CONDITION,要么是CANCELLEDprivate 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;elset.nextWaiter = node;lastWaiter = node;return node;}//方法的作用是移除取消的节点 。方法本身只有在持有锁的时候会被调用 。方法会遍历当前condition队列,将所有非Condition状态的节点移除 。private void unlinkCancelledWaiters() {Node t = firstWaiter;Node trail = null;while (t != null) {Node next = t.nextWaiter;if (t.waitStatus != Node.CONDITION) {t.nextWaiter = null;if (trail == null)firstWaiter = next;elsetrail.nextWaiter = next;if (next == null)lastWaiter = trail;}elsetrail = t;t = next;}}【2】核心signal方法与signalAll方法
public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);}public final void signalAll() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignalAll(first);}private void doSignal(Node first) {do {if ( (firstWaiter = first.nextWaiter) == null)lastWaiter = null;first.nextWaiter = null;} while (!transferForSignal(first) &&(first = firstWaiter) != null);}private void doSignalAll(Node first) {lastWaiter = firstWaiter = null;do {Node next = first.nextWaiter;first.nextWaiter = null;transferForSignal(first);first = next;} while (first != null);}final boolean transferForSignal(Node node) {//如果不能更改waitStatus,则表示该节点已被取消if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;Node p = enq(node);int ws = p.waitStatus;if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;}

推荐阅读