Semaphore 的许可到底是什么?为什么多 release 一次会出问题?这篇用小实验把许可数、超时、负初始值、所有者和队列顺序一个个量出来(ReentrantLock 的队列见 AQS 一篇,CountDownLatch 与 CyclicBarrier 在已有文章里)。
Semaphore(1),12 个任务各占用 100 ms:同时进入临界区的最大数量 = 1,总耗时 1279 ms(12 / 1 × 100 ms ≈ 1200 ms) Semaphore(3),12 个任务各占用 100 ms:同时进入临界区的最大数量 = 3,总耗时 433 ms(12 / 3 × 100 ms ≈ 400 ms) Semaphore(6),12 个任务各占用 100 ms:同时进入临界区的最大数量 = 6,总耗时 218 ms(12 / 6 × 100 ms ≈ 200 ms)
Semaphore(2) 初始 availablePermits = 2 没有 acquire 就 release 3 次 → availablePermits = 5(许可数可以超过初始值,没有上限) tryAcquire(5) = true,之后 availablePermits = 0(一次拿多个许可) tryAcquire(1) 在没有许可时 = false;tryAcquire(100 ms) = false(超时返回 false,不抛异常) release(3) 后 drainPermits() = 3,之后 availablePermits = 0 Semaphore(-2):availablePermits = -2,release 2 次后 = 0,tryAcquire() = false,再 release 1 次后 tryAcquire() = 1/true
Semaphore(0) 当信号用:另一个线程 release 之后 acquire 才返回,等了 160 ms;持有者线程不同(acquire 的线程 ≠ release 的线程):没有「所有者」的概念 主线程 acquire 之后,别的线程替它 release:availablePermits = 1(没有报错) 阻塞在 acquire 的线程被 interrupt → InterruptedException,许可数仍是 0
非公平信号量:主线程持有唯一许可,T1..T5 依次排队;主线程 release 前 hasQueuedThreads = true,queueLength = 5
获得许可的顺序 = [T1, T2, T3, T4, T5]
公平信号量:主线程持有唯一许可,T1..T5 依次排队;主线程 release 前 hasQueuedThreads = true,queueLength = 5
获得许可的顺序 = [T1, T2, T3, T4, T5]