AQS Condition

最近面试被问到java concurrent包下有哪些熟悉的,用过的工具。因此来回顾一下,这些工具的底层实现,AbstractQueuedSynchronizer。在网上看到了其他人的一些技术博客,我将源码贴出,分享下自己不同的见解。
clipboard.png
clipboard.png

分析源码

对于初看源码的我来说,很奇怪,为什么明明“waitThread1”已经拿到锁的情况下,而“singalThread”还能获取同样的锁而运行呢。这就得看源码才能分析明白。
一开始waitThread拿到了锁,然后调用了condition调用了await方法。
看看await方法:
clipboard.png

  1. 首先方法中会构建一个node用来表示该node现在在Condition的queue中。Condition的queue维护着一连串的node,当前线程被包含在其中。

  2. 接下来fullyRelease方法会将AQS的当前状态即state置为0(这里说的是具体的ReentrantLock的tryRelease实现方式,因为它是独占锁。)fullyRelease其中还会将AQS中维护的queue(其中同样是node,只是Condition中的node记录的是等待condition的node,AQS中的queue是等待锁的node)中的线程释放出来。注意,执行完这一步之后,若另一个线程singalThread由于lock而得不到锁,已经在AQS的queue中,处于wait状态,这时他将被唤醒,然后获取到锁,从AQS的queue中删除。

  3. 当singalThread执行完singal的之中,就会将condition中的node移到AQS的queue上去。
    具体代码在condition中的signal方法中:

clipboard.png

将其node的状态改为SIGNAL,注意这个时候一般node还没有被唤醒。
clipboard.png

通常上面这一句不会为true,除非没有能把目前node的状态改为SIGNAL,或者node state大于0了,这个时候说明任务呗取消了,那么以上两种情况都直接唤醒线程。除了上述两种情况外,由signalthread的unlock操作唤醒在AQS上的线程。

总结

总的来说,操作顺序是:

  1. waitthread lock

  2. Signalthread lock 进入AQS队列wait

  3. waitthread await 唤醒 Signalthread,Signalthread成功获得锁

  4. Signalthread signal 将waitthread 状态变为signal并将其从condition queue转到AQS queue

  5. Signalthread unlock 使waitthread再次获得锁 执行余下代码。
    当然这是理由状态下,为了讨论AQS及condition的原理,实际的操作时序也有可能变化。


curlevel2
1 声望0 粉丝