news 2026/7/8 1:20:31

CountdownLatch 源码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CountdownLatch 源码

构造方法

publicCountDownLatch(intcount){if(count<0)thrownewIllegalArgumentException("count < 0");this.sync=newSync(count);}

Sync

privatestaticfinalclassSyncextendsAbstractQueuedSynchronizer{privatestaticfinallongserialVersionUID=4982264938641297070L;Sync(intcount){setState(count);}intgetCount(){returngetState();}// await调用:共享模式尝试获取锁protectedinttryAcquireShared(intacquires){// state == 0 返回1(获取成功),否则-1(阻塞)return(getState()==0)?1:-1;}// countDown调用:共享模式释放锁,state自减1protectedbooleantryReleaseShared(intreleases){// CAS循环自旋减statefor(;;){intc=getState();if(c==0)returnfalse;intnextc=c-1;if(compareAndSetState(c,nextc))returnnextc==0;}}}

countdown

publicvoidcountDown(){sync.releaseShared(1);}

releaseShared

publicfinalbooleanreleaseShared(intarg){if(tryReleaseShared(arg)){doReleaseShared();returntrue;}returnfalse;}

tryReleaseShared

protectedbooleantryReleaseShared(intreleases){for(;;){intc=getState();if(c==0)returnfalse;intnextc=c-1;if(compareAndSetState(c,nextc))returnnextc==0;}}

doReleaseShared

  • 遍历 AQS 阻塞队列,唤醒头部等待节点;
  • 等待线程被 unpark 唤醒,再次执行tryAcquireShared;
  • 如果 state=0,返回 1,获取共享锁成功,退出阻塞逻辑,主线程继续执行后续代码
privatevoiddoReleaseShared(){for(;;){Nodeh=head;if(h!=null&&h!=tail){intws=h.waitStatus;// 头节点标记SIGNAL,说明后继需要唤醒if(ws==Node.SIGNAL){// CAS重置头节点状态为0,防止重复唤醒if(!compareAndSetWaitStatus(h,Node.SIGNAL,0))continue;// 唤醒头节点的后继等待线程(主线程)unparkSuccessor(h);}// 无等待线程,设置PROPAGATE传播标记elseif(ws==0&&!compareAndSetWaitStatus(h,0,Node.PROPAGATE))continue;}// 循环终止条件:中途head发生变化,说明有新节点被唤醒,继续循环传播if(h==head)break;}}

await

publicvoidawait()throwsInterruptedException{sync.acquireSharedInterruptibly(1);}

acquireSharedInterruptibly

publicfinalvoidacquireSharedInterruptibly(intarg)throwsInterruptedException{if(Thread.interrupted())thrownewInterruptedException();if(tryAcquireShared(arg)<0)doAcquireSharedInterruptibly(arg);}

tryAcquireShared

protectedinttryAcquireShared(intacquires){return(getState()==0)?1:-1;}

doAcquireSharedInterruptibly

  • 把当前主线程封装成 共享 SHARED 类型 Node
  • CAS 把节点加入 AQS 阻塞双向链表尾部
  • 循环自旋:
    1. 如果当前节点是队列头节点,再次调用 tryAcquireShared
    2. 执行 parkAndCheckInterrupt(),调用 LockSupport.park()
    3. 当前线程挂起,卡住,不再往下执行,等待其他线程 countDown 把 state 降到 0 唤醒
privatevoiddoAcquireSharedInterruptibly(intarg)throwsInterruptedException{// 1. 创建共享SHARED类型节点,加入队尾finalNodenode=addWaiter(Node.SHARED);booleanfailed=true;try{for(;;){// 获取当前节点前驱finalNodep=node.prev;// 如果前驱是头结点,有资格尝试获取共享锁if(p==head){intr=tryAcquireShared(arg);if(r>=0){// 获取共享锁成功,设置新head,传播唤醒setHeadAndPropagate(node,r);p.next=null;// help GCfailed=false;return;}}// 调整节点waitStatus,无资格则park阻塞if(shouldParkAfterFailedAcquire(p,node)&&parkAndCheckInterrupt())thrownewInterruptedException();}}finally{if(failed)cancelAcquire(node);}}

setHeadAndPropagate

privatevoidsetHeadAndPropagate(Nodenode,intpropagate){Nodeh=head;// 保存旧头setHead(node);// 当前等待节点晋升为新head,清空thread、prev// propagate>0 说明还有剩余共享许可,需要继续唤醒后继if(propagate>0||h==null||h.waitStatus<0||(h=head)==null||h.waitStatus<0){Nodes=node.next;// 如果下一个节点也是共享节点,继续唤醒传播if(s==null||s.isShared())doReleaseShared();}}

getCount

publiclonggetCount(){returnsync.getCount();}

总结

await

latch.await() → sync.acquireSharedInterruptibly(1) → tryAcquireShared 返回 -1 → doAcquireSharedInterruptibly(1) addWaiter(SHARED) 入队 for 自旋 tryAcquireShared 失败 shouldParkAfterFailedAcquire 设置前驱 SIGNAL parkAndCheckInterrupt() 阻塞主线程

countdown

latch.countDown() → sync.releaseShared(1) → tryReleaseShared CAS state到0,返回true → doReleaseShared() CAS清空head SIGNAL标记 unparkSuccessor 唤醒主线程 等待线程被唤醒,回到 doAcquireSharedInterruptibly 自旋 tryAcquireShared 返回 1 setHeadAndPropagate 晋升新 head、传播唤醒 退出阻塞,await执行完毕
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 1:19:52

第一单元: 构建基本布局

第一单元&#xff1a;构建基本布局&#x1f4a1; 核心概念&#xff1a;Jetpack Compose 使用声明式 UI 范式&#xff0c;你只需描述界面"长什么样"&#xff0c;Compose 会自动处理如何渲染。通过可组合函数&#xff08;Composable Functions&#xff09;&#xff0c;…

作者头像 李华
网站建设 2026/7/8 1:19:16

OpenHarmony AppStorage 全局状态管理跨页面传参开发(API Version23 + 适配版)

摘要ArkUI 提供 AppStorage 作为应用全局持久化内存状态容器&#xff0c;可实现页面、自定义组件、弹窗之间跨层级、跨页面数据共享&#xff0c;适用于用户登录信息、全局主题、配置开关、全局缓存参数等全局数据存储场景。API Version23 重构 AppStorage 底层数据监听、同步刷…

作者头像 李华
网站建设 2026/7/8 1:19:08

MH迈汇:从公开信息出发,观察长期一致性与用户体验路径

外汇市场信息更新频繁&#xff0c;平台口碑的形成更依赖长期一致性&#xff1a;入口是否好找、说明是否前后一致、提示是否稳定出现。谈到MH迈汇时&#xff0c;下面从稳定体验与信息呈现等角度做一次正面观察。外汇相关信息更新频繁&#xff0c;平台将关键提示与解释呈现得更清…

作者头像 李华
网站建设 2026/7/8 1:14:28

15个实用的团队协作平台,敏捷开发

15个实用的团队协作平台&#xff0c;敏捷开发 **15个实用的团队协作平台&#xff0c;助力敏捷开发高效落地** 在快节奏的软件开发领域&#xff0c;敏捷开发已成为团队的标配方法论。但要想真正实现“快速迭代、高效协同”&#xff0c;离不开合适的协作工具支撑。本文将盘点15…

作者头像 李华
网站建设 2026/7/8 1:12:14

GPT生成的代码本地能跑,上线为什么就报错?5个隐性问题必须检查

使用 ChatGPT 或 Codex 写代码时&#xff0c;经常会遇到一种情况&#xff1a;代码在本地测试一切正常&#xff0c;部署到服务器后却突然报错&#xff1b;有时甚至刚上线还能运行&#xff0c;用户数量一多就开始出现各种异常。问题通常不是 GPT 生成的代码完全不能用&#xff0c…

作者头像 李华
网站建设 2026/7/8 1:11:44

上位机学习第五天

天气&#xff1a;大雨今天学了装箱拆箱&#xff0c;委托&#xff0c;委托刚开始看一直看不懂&#xff0c;换了个视频看就好多了&#xff0c;果然哪怕同样的知识点&#xff0c;不同的人讲起来效果也不一样

作者头像 李华