jdk源码解析七之Condition 素颜马尾好姑娘i 2023-02-21 11:42 53阅读 0赞 ### 文章目录 ### * Condition * * newCondition * await * signal * signalAll * 总结 # Condition # ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70] 主要看java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject ## newCondition ## public Condition newCondition() { return sync.newCondition(); } final ConditionObject newCondition() { return new ConditionObject(); } ## await ## public final void await() throws InterruptedException { //中断处理 if (Thread.interrupted()) throw new InterruptedException(); //添加下一个节点到等待队列 Node node = addConditionWaiter(); //阻塞时候,会释放锁 int savedState = fullyRelease(node); //1) 当在被通知前被中断则将中断模式设置为THROW_IE; // 2) 当在被通知后则将中断模式设置为REINTERRUPT(因为acquireQueued不会响应中断)。 int interruptMode = 0; //如果不在同步队列,则阻塞 while (!isOnSyncQueue(node)) { //阻塞当前线程 //在另一个线程调用sign和unlock之后唤醒 //调用sign,将当前等待线程添加到同步线程 //然后调用unlock释放同步线程 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 //删除状态不为CONDITION的节点 unlinkCancelledWaiters(); //根据中断模式抛出异常 if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } private Node addConditionWaiter() { //获取上一个等待节点 Node t = lastWaiter; // If lastWaiter is cancelled, clean out. if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } //创建一个新的节点,并标记CONDITION Node node = new Node(Thread.currentThread(), Node.CONDITION); //如果上一个等待节点为空,则设置为第一个节点 if (t == null) firstWaiter = node; else //否则设置为下一个节点 t.nextWaiter = node; lastWaiter = node; return node; } final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); //释放所有锁? if (release(savedState)) { failed = false; //返回保存状态 return savedState; } else { throw new IllegalMonitorStateException(); } } finally { //失败,则标记状态为取消 if (failed) node.waitStatus = Node.CANCELLED; } } final boolean isOnSyncQueue(Node node) { //如果节点在条件队列或者节点前置为null,则阻塞 //prev为null的时候,说明是头节点,而头结点一般是空node,所以不可能是头结点 //name也就是处于transferForSignal方法中compareAndSetWaitStatus和enq之间的中间状态 if (node.waitStatus == Node.CONDITION || node.prev == null) return false; //如果有后续任务,说明被其他线程修改,已经入队 if (node.next != null) // If has successor, it must be on queue return true; /* * node.prev can be non-null, but not yet on queue because * the CAS to place it on queue can fail. So we have to * traverse from tail to make sure it actually made it. It * will always be near the tail in calls to this method, and * unless the CAS failed (which is unlikely), it will be * there, so we hardly ever traverse much. */ //状态不是CONDITION,且前置节点不为null,后置节点为null,可能是尾节点,则从后查找 //从后到前查找是否有node,如果没有说明还正在添加则阻塞 //也就是enq调用compareAndSetTail存在并发修改失败 return findNodeFromTail(node); } //尾部查找node节点 private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } } private int checkInterruptWhileWaiting(Node node) { /* 没有异常,返回0 中断在通知之前,THROW_IE 中断在通知之后,REINTERRUPT */ return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; } final boolean transferAfterCancelledWait(Node node) { //当前节点状态为CONDITION,中断在通知之前 //设置状态为0,将取消的线程添加到同步队列中 if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } /* * If we lost out to a signal(), then we can't proceed * until it finishes its enq(). Cancelling during an * incomplete transfer is both rare and transient, so just * spin. */ /* 节点不是CONDITION状态,这说明中断在通知之后 自旋添加到队列中 */ while (!isOnSyncQueue(node)) Thread.yield(); //线程在通知之后被取消 return false; } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //返回前端节点 final Node p = node.predecessor(); /*如果是当前头节点且再次获取锁成功 */ if (p == head && tryAcquire(arg)) { //设置头结点为当前节点,以及清空当前节点的pre和thread setHead(node); //释放GC p.next = null; // help GC //标记正常执行 failed = false; return interrupted; } //检查并修改一个节点的状态,当该节点获取锁失败时。返回true如果线程需要阻塞。 if (shouldParkAfterFailedAcquire(p, node) && //这里执行阻塞 parkAndCheckInterrupt()) //标记已中断 interrupted = true; } } finally { if (failed) cancelAcquire(node); } } private void unlinkCancelledWaiters() { //删除状态不为CONDITION的节点 //trail ->t->next Node t = firstWaiter; //记录上一个状态为CONDITION的节点 Node trail = null; while (t != null) { Node next = t.nextWaiter; if (t.waitStatus != Node.CONDITION) { t.nextWaiter = null; if (trail == null) firstWaiter = next; else //删除t节点 trail.nextWaiter = next; if (next == null) lastWaiter = trail; } else trail = t; t = next; } } private void reportInterruptAfterWait(int interruptMode) throws InterruptedException { //抛出中断异常 if (interruptMode == THROW_IE) throw new InterruptedException(); else if (interruptMode == REINTERRUPT) //中断 selfInterrupt(); } ## signal ## public final void signal() { //发送信号的是否是当前线程,如果不是则异常 //确保signal在lock之后,且同一个线程 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //获取第一个等待节点 Node first = firstWaiter; if (first != null) //发送信号 doSignal(first); } private void doSignal(Node first) { do { //删除first节点,并设置firstWaiter为下一个节点 //如果下一个节点为null,则清空lastWaiter if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; //清空first下一个节点 first.nextWaiter = null; } while ( //将删除的first节点添加到同步队列 //如果添加失败,说明已经有其他线程添加成功了 //却白first不为null,再次遍历 !transferForSignal(first) && (first = firstWaiter) != null); } 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添加到同步队列最后,且返回上一个节点 Node p = enq(node); //获取入队前前置节点状态 int ws = p.waitStatus; //前置节点为取消状态的时候,也就是说他不会在被唤醒,如果当前线程执行unlock执行unpark操作的时候,唤醒的是一个取消节点 //而这不是我们愿意看到的,我们希望唤醒的是一个正常节点,这里提前唤醒下一个正常节点线程.在正常节点被唤醒后,会竞争锁,竞争锁成功后,会删除取消的节点 //前置节点为取消状态,直接唤醒 //或者为非取消状态则修改为SIGNAL,如果失败则唤醒 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) //唤醒当前线程 LockSupport.unpark(node.thread); //添加同步队列成功 return true; } ## signalAll ## public final void signalAll() { //非当前获取独占锁线程异常 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //获取第一个等待节点 Node first = firstWaiter; if (first != null) //遍历添加所有等待节点到同步队列 doSignalAll(first); } private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } ## 总结 ## await时,会释放锁 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 1] await有2个阻塞状态,第一个阻塞状态等待当前节点添加到同步队列 第二个阻塞状态是竞争锁. ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 2] ConditionObject维护了2个节点,当await时将节点添加到等待队列中 当signal*时,将队列节点添加到同步队列head和tail中.在执行unlock的时候被唤醒. 但是在signal*时,如果上一个节点出现取消状态或者上一个同步队列节点修改状态失败,则提前唤醒当前节点 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 3] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 4] 对CAS中间状态的维护 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 5] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 6] [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70]: https://img-blog.csdnimg.cn/20200603201138185.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 1]: https://img-blog.csdnimg.cn/20200604120048212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 2]: https://img-blog.csdnimg.cn/20200604120415313.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 3]: https://img-blog.csdnimg.cn/20200604113402933.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 4]: https://img-blog.csdnimg.cn/20200604113420921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 5]: https://img-blog.csdnimg.cn/20200604113431933.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw_size_16_color_FFFFFF_t_70 6]: https://img-blog.csdnimg.cn/20200604113450570.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L051YW5fRmVuZw==,size_16,color_FFFFFF,t_70
相关 jdk源码解析八之NIO 文章目录 Buffer ByteBuffer MappedByteBuffer DirectByteBu 素颜马尾好姑娘i/ 2023年02月22日 05:12/ 0 赞/ 131 阅读
相关 jdk源码解析八之BIO 文章目录 字节流 InputStream FilterInputStream ByteArrayInputSt 怼烎@/ 2023年02月21日 14:21/ 0 赞/ 45 阅读
相关 jdk源码解析七之Condition 文章目录 Condition newCondition await signal signalAll 素颜马尾好姑娘i/ 2023年02月21日 11:42/ 0 赞/ 54 阅读
相关 jdk源码解析七之ReadWriteLock 文章目录 ReadWriteLock ReentrantReadWriteLock 构造 获取读写锁 灰太狼/ 2023年02月21日 11:42/ 0 赞/ 52 阅读
相关 jdk源码解析三之CopyOnWriteArrayList 文章目录 CopyOnWriteArrayList add remove get 末蓝、/ 2023年02月20日 12:07/ 0 赞/ 37 阅读
相关 jdk源码解析三之ConcurrentHashMap 文章目录 ConcurrentHashMap put 初始化 扩容 ge た 入场券/ 2023年02月20日 12:07/ 0 赞/ 48 阅读
相关 jdk11源码--ReentrantLock之Condition源码分析 > 更多java源码分析请见:jdk11源码分析系列文章专栏:[Java11源码分析][Java11] 文章目录 欢迎关注本人公众号 概述 创建Con 电玩女神/ 2021年12月21日 06:23/ 0 赞/ 391 阅读
还没有评论,来说两句吧...