发布于2026-07-12 阅读(0)
扫一扫,手机访问
说到 Semaphore,它的底层实现其实很简单——就是基于 AQS(AbstractQueuedSynchronizer)那一套队列管理和状态控制机制。不过,它不像 ReentrantLock 那样跟线程绑定,而是纯粹靠一个整数状态(state)来代表当前还剩多少许可。所有同步逻辑,获取、释放、阻塞、唤醒,全都围绕这个整型数字展开。

具体来说,AQS 的 state 字段在 Semaphore 里直接被当作可用许可计数器来用。构造时通过 setState(permits) 设好初始值,那就是总许可数。调用 acquire() 时,state -= 1,如果减完后变负数,说明许可用光了,当前线程就得乖乖入队等着。而 release() 则是 state += 1,释放后立马尝试唤醒队列头部的等待线程。整个过程不记录哪个线程持有许可——换句话说,任何线程都可以释放,不像锁那样有“持有者”的概念。
setState(permits),初始值即为总许可数acquire() 对应 state -= 1;若减后为负,说明无许可可用,当前线程入队等待release() 对应 state += 1;释放后立即尝试唤醒队列头部等待线程Semaphore 用的是 AQS 的共享模式(shared mode),核心就是重写 tryAcquireShared(int) 方法。这个方法返回值决定是否获取成功:≥0 表示成功,负数表示失败。内部通过 CAS 原子更新 state,避免竞态条件;如果 CAS 失败,就会进入 AQS 的 doAcquireSharedInterruptibly 流程,把等待线程封装成 Node 节点,塞进 CLH 同步队列,挂起前还会检查前驱节点的状态,保证唤醒链足够可靠。
Semaphore 提供了公平和非公平两种策略,区别就体现在 tryAcquireShared 的具体实现里。
hasQueuedPredecessors(),如果队列里有线程在排队,就放弃抢锁,老老实实排到队尾release() 最终会调用 tryReleaseShared():先原子地将 state 加 1,然后返回 true;之后 AQS 自动调用 doReleaseShared(),从队列头开始唤醒一个或多个等待线程。因为是共享模式,被唤醒的线程会再次调用 tryAcquireShared 去竞争许可,这样就形成了“释放→唤醒→再竞争”的循环,一个释放操作可以带动多个线程依次获得许可,效率很高。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8