登录
首页 >  文章 >  java教程

AQS共享模式解析:Semaphore与CountDownLatch区别

时间:2026-04-30 19:24:40 469浏览 收藏

本文深入剖析了AQS共享模式下Semaphore与CountDownLatch的核心差异——二者虽共用AbstractQueuedSynchronizer的state字段,但语义截然相反:Semaphore将state定义为“剩余许可数”(越大越空闲,支持多次获取/释放、限流与公平性控制),而CountDownLatch将其视为“待完成任务数”(越小越接近完成,仅做一次性倒计时门控,不可重置且无公平机制);这一根本区别直接决定了tryAcquireShared的返回逻辑、阻塞/放行时机、release操作的加减方向,以及整体行为模型,看懂state的语义是真正理解两者源码与设计思想的关键突破口。

怎么通过分析 AQS 的共享模式源码理解 Semaphore 与 CountDownLatch 的底层差异

看懂 AQS 共享模式的 state 含义是关键起点

两者都用 AbstractQueuedSynchronizerstate 字段存一个整数,但语义完全不同:Semaphorestate 是「剩余许可数」,越大表示越空闲;CountDownLatchstate 是「待完成任务数」,越小越接近释放等待线程。这个根本差异直接决定所有行为——比如 tryAcquireShared 返回值:Semaphore 返回负数表示“没许可了”,CountDownLatch 返回负数表示“计数还没到 0”。不厘清这点,看源码只会越看越乱。

tryAcquireShared 的返回逻辑决定阻塞/放行时机

这是共享模式下最核心的钩子方法,两者的实现路径截然不同:

  • Semaphore.NonfairSync.nonfairTryAcquireShared:用 available - acquires 计算剩余,若结果
  • CountDownLatch.Sync.tryAcquireShared:直接比较 getState() == 0,等于 0 才返回 1(放行),否则返回 -1(阻塞)

注意:Semaphore 支持一次 acquire(3) 拿 3 个许可,而 CountDownLatch 的 await() 永远只关心“是否为 0”,不支持“等一半”。这也是为什么 Semaphore 能做限流,CountDownLatch 只能做一次性门控。

release 操作对 state 的修改方向相反

释放行为暴露了设计意图的对立性:

  • Semaphore.release() 调用 tryReleaseShared(releases),本质是 state += releases —— 把许可还回池子
  • CountDownLatch.countDown() 调用 tryReleaseShared(1),本质是 state -= 1 —— 把计数往下减

这种加减方向的差异不是偶然:Semaphore 的许可是“资源池”,用完要归还;CountDownLatch 的计数是“倒计时”,走完即终止。这也解释了为什么 CountDownLatch 不可重置,而 Semaphorerelease 可以反复调用甚至超额释放(只要没溢出)。

公平性开关只在 Semaphore 中生效,CountDownLatch 无此概念

Semaphore 构造时可传 fair = true,启用 FairSync,其 tryAcquireShared 会先检查同步队列是否有等待者,再决定是否让当前线程插队;而 CountDownLatch 根本没有公平/非公平变体——它的 await() 从不“争抢”,只“守候”,所有等待线程都在队列里安静排队,直到 state 归零被统一唤醒。所以你在 CountDownLatch 源码里找不到 FairSync 或任何与公平策略相关的分支。

理论要掌握,实操不能落!以上关于《AQS共享模式解析:Semaphore与CountDownLatch区别》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>