深入浅出AQS之条件队列 (3)

至此条件队列await操作全部分析完毕。signal()方法相对容易一些,一起看源码分析下:

//条件队列唤醒入口 public final void signal() { //如果不是独占锁则抛出异常,再次说明条件队列只适用于独占锁 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //如果条件队列不为空,则进行唤醒操作 Node first = firstWaiter; if (first != null) doSignal(first); } //该方法就是把一个有效节点从条件队列中删除并加入同步队列 //如果失败则会查找条件队列上等待的下一个节点直到队列为空 private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) &&(first = firstWaiter) != null); } //将节点加入同步队列 final boolean transferForSignal(Node node) { //修改节点状态,这里如果修改失败只有一种可能就是该节点被取消,具体看上面await过程分析 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; //该方法很熟悉了,跟独占锁入队方法一样,不赘述 Node p = enq(node); //注:这里的p节点是当前节点的前置节点 int ws = p.waitStatus; //如果前置节点被取消或者修改状态失败则直接唤醒当前节点 //此时当前节点已经处于同步队列中,唤醒会进行锁获取或者正确的挂起操作 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } 三、总结

相比于独占锁跟共享锁,条件队列可能是最不受关注的了,但由于它是阻塞队列实现的关键组件,还是有必要了解一下其中的原理。其实我认为关键点有两条,第一是条件队列是建立在某个具体的锁上面的,第二是条件队列跟同步队列是两个队列,前者依赖条件唤醒后者依赖锁释放唤醒,了解了这两点以后搞清楚条件队列就不是什么难事了。

至此,Java同步器AQS中三大锁模式就都分析完了。虽然已经尽力思考,尽量写的清楚,但鉴于水平有限,如果有纰漏的地方,欢迎广大读者指正。
明天就是国庆长假了,我自己也计划出国玩一趟,散散心。
提前祝广大朋友国庆快乐。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgyjgp.html