连载中 18/21

协作三件套:CountDownLatch、CyclicBarrier、Semaphore

2026-10-31 · 32 阅读 · 0 评论 · 0 赞

它们不是锁,是调度器

锁解决「不能同时干」,这一篇的工具解决「什么时候一起干」——等待与配额。底层全是第 10 篇的 AQS 共享模式:state 存计数,tryAcquireShared 判定,传播唤醒接力放行。一个 AQS,三种人设。

CountDownLatch:一次性门闩

语义:计数器归零之前,所有 await 的线程原地等待;每次 countDown 减一。典型场景——主线程把任务拆给 N 个线程,等全部完工再汇总:

CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    executor.submit(() -> {
        try { doQuery(); } finally { latch.countDown(); }   // 干完减一
    });
}
latch.await();      // 阻塞,直到三个都干完
mergeResults();

两个注意:countDown 必须放 finally——任务抛异常也要减,否则永远等不到归零,主线程挂在 WAITING;不可重用,归零即报废。定位:「等多个固定事件」的一次性协调。

CyclicBarrier:人齐再走

语义反过来:N 个线程各自干到栅栏处 await,人齐了才一起放行,而且可循环重用(Cyclic 的本意)。适合多线程分阶段协作——各算各的,每轮结束对齐一次再进下一轮:

CyclicBarrier barrier = new CyclicBarrier(4, () ->
        System.out.println("一轮计算完成,开始合并"));   // 人齐后执行的回调

// 每个工作线程干完当前轮次:
barrier.await();        // 等其他三个到齐
computeNextPhase();

与 CDL 的本质区别:CDL 等的是「事件完成」——事件自己调 countDown,和等待者没关系;Barrier 等的是「同伴到齐」——大家互相等。另外 Barrier 有 broken 机制:某个线程等待中被中断,整轮栅栏作废(BrokenBarrierException),不会出现一部分人过了栅栏、另一部分还挂在原地的不一致。

Semaphore:配额发放

语义:state 是剩余许可,acquire 拿一个(没有就排队),release 还一个。两大场景:限流——只放 N 个线程同时进;资源池——连接池、对象池的经典实现骨架:

Semaphore permits = new Semaphore(10);          // 最多 10 个并发

public Data query() throws InterruptedException {
    permits.acquire();                          // 拿许可,没有就排队
    try { return doQuery(); }
    finally { permits.release(); }              // 用完必须还
}

tryAcquire(3, TimeUnit.SECONDS) 支持超时;构造第二个参数传 true 开公平模式。和第 8 篇呼应一下:统计类计数用 LongAdder,限流配额这种要精确控制进出的,用 Semaphore——两者看似都是数字增减,语义完全不同。

一句话记住三件套

CDL 等事件(一次性)、Barrier 等同伴(可循环)、Semaphore 管配额(可增减)。API 都很简单,难点从来不在用法,而在识别场景——先问自己:我是在等事件、等人齐,还是在控数量?对号入座。下一篇解决更高级的问题:多个异步任务怎么优雅地编排——CompletableFuture。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Java#CountDownLatch#CyclicBarrier#Semaphore#JUC

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10113 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9876 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9306 阅读 · 21 评论 · 287 赞