精华帖 (0) :: 良好帖 (7) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-06-17
最后修改:2011-08-10
在上一篇中,我们了解了下J.U.C的锁的获取与释放的过程,这个过程主要通过在A.Q.S中维持一个等待队列来实现,其中我们也提到了,在A.Q.S中除了一个等待队列之外,还有一个Condition队列,在了解Condition队列之前,先来看一下Condition是怎么回事:
写道
The synchronizer framework provides a ConditionObject class for use by synchronizers that maintain exclusive synchronization and conform to the Lock interface. Any number of condition objects may be attached to a lock object, providing classic monitor-style await, signal, and signalAll operations, including those with timeouts, along with some inspection and monitoring methods.
上面的这一段内容摘自Doug Lea的AQS论文,从上面这一段话可以看出,Condition主要是为了在J.U.C框架中提供和Java传统的监视器风格的wait,notify和notifyAll方法类似的功能,那么先来解释一下这三个方法的作用:
那么Condition是如何实现wait,notify和notifyAll方法的功能呢?我们接下来看: 在Condition中,wait,notify和notifyAll方法分别对应了await,signal和signalAll方法,当然Condition也提供了超时的、不可被中断的await()方法,不过我们主要还是看一看await,notify和notifyAll的实现,先看await: 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) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } 整个await的过程如下:
可以看到,这个await的操作过程和Object.wait()方法是一样,只不过await()采用了Condition队列的方式实现了Object.wait()的功能。 signal和signalAll方法:在了解了await方法的实现以后,signal和signalAll方法的实现就相对简单了,先看看signal方法: public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } 这里先判断当前线程是否持有锁,如果没有持有,则抛出异常,然后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么:
private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); } 这个while循环的作用就是将firstWaiter往Condition队列的后面移一位,并且唤醒first,看看while循环中tranferForSignal:
final boolean transferForSignal(Node node) { /* * If cannot change waitStatus, the node has been cancelled. */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ Node p = enq(node); int c = p.waitStatus; if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } 这段代码的作用就是修改Node的waitStatus为0,然后将Node插入到等待队列中,并且唤醒Node。 signalAll和signal方法类似,主要的不同在于它不是调用doSignal方法,而是调用doSignalAll方法: private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } 这个方法就相当于把Condition队列中的所有Node全部取出插入到等待队列中去。
总结:在了解了await(),signal()和signalAll方法的实现以后,我们再来通过一副gif动画来看一看这一个整体的过程:
PS. 原文在:Java并发编程J.U.C之Condition 请大家关注:黄金档 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-06-17
牛逼,写的很好,学习中。。。
|
|
返回顶楼 | |
发表时间:2011-06-17
顶!非常不错!学习ing
|
|
返回顶楼 | |
发表时间:2011-06-17
不错,写的挺详细。 是有一个J.U.C系列吗? 期待LZ的下一篇哈
|
|
返回顶楼 | |
发表时间:2011-06-17
agapple 写道 不错,写的挺详细。 是有一个J.U.C系列吗? 期待LZ的下一篇哈
是的,会写一个J.U.C的系列的,呵呵,敬请关注下一篇。 |
|
返回顶楼 | |
发表时间:2011-06-17
goldendoc 写道 agapple 写道 不错,写的挺详细。 是有一个J.U.C系列吗? 期待LZ的下一篇哈
是的,会写一个J.U.C的系列的,呵呵,敬请关注下一篇。 期待啊~ |
|
返回顶楼 | |
发表时间:2011-06-17
不错, 期待。
|
|
返回顶楼 | |
发表时间:2011-06-18
就想多学习学习concurrent 多谢lz 期待后续的帖子
|
|
返回顶楼 | |
发表时间:2011-06-19
细看了一下,讲的很好,很清晰。
PS:有两个错别字,不过不影响阅读及理解; 1、Object.notify()方法只有在当前线程只有Object的监视器的时候才能够调用,不然就会抛出异常。 2、和wait()方法一样,Object.notifyAll()方法只有在当前线程只有Object的监视器的时候才能够调用,不然就会抛出异常。 |
|
返回顶楼 | |
发表时间:2011-06-21
虽然没有用到,但是博主的分享精神 good
|
|
返回顶楼 | |