Semaphore 維護一組「許可證」,線程調用 acquire() 獲取許可(無則阻塞),用完調用 release() 歸還。構造函數參數指定許可證總數,可選 fair 參數控制公平性(FIFO vs 非公平)。
如:數據庫連接池限制 10 並發、文件同時寫入限制 5 個線程、廁所有 5 個坑位同時容納 5 人。
import java.util.concurrent.*;
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3); // 允許 3 並發
for (int i = 0; i < 10; i++) {
es.execute(() -> {
try {
sp.acquire(); // 獲取許可
System.out.printf("線程 %s 進入,當前並發: %d%n",
Thread.currentThread().getName(), 3 - sp.availablePermits());
Thread.sleep(2000); // 模擬業務
System.out.printf("線程 %s 即將離開%n", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
sp.release(); // 歸還許可
System.out.printf("線程 %s 離開,當前並發: %d%n",
Thread.currentThread().getName(), 3 - sp.availablePermits());
}
});
}
es.shutdown();
}
}
new Semaphore(1) 等價於互斥鎖,但更靈活:可由線程 A acquire(),線程 B release(),適用於死鎖恢復等特殊場景。
CyclicBarrier 讓一組線程相互等待,直到所有線程都到達屏障點(調用 await()),然後同時繼續執行。可選構造參數 Runnable barrierAction 在所有線程到達後、繼續前由最後一個到達的線程執行。
import java.util.concurrent.*;
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3); // 3 個線程
for (int i = 0; i < 3; i++) {
service.execute(() -> {
try {
Thread.sleep((long)(Math.random() * 10000)); // 隨機準備時間
System.out.printf("線程 %s 到達集合點1,已有 %d 個到達,%s%n",
Thread.currentThread().getName(),
cb.getNumberWaiting() + 1,
cb.getNumberWaiting() == 2 ? "都到齊了,繼續前進" : "正在等候");
cb.await(); // 等待其他線程
Thread.sleep((long)(Math.random() * 10000));
System.out.printf("線程 %s 到達集合點2,已有 %d 個到達,%s%n",
Thread.currentThread().getName(),
cb.getNumberWaiting() + 1,
cb.getNumberWaiting() == 2 ? "都到齊了,繼續前進" : "正在等候");
cb.await();
Thread.sleep((long)(Math.random() * 10000));
System.out.printf("線程 %s 到達集合點3,已有 %d 個到達,%s%n",
Thread.currentThread().getName(),
cb.getNumberWaiting() + 1,
cb.getNumberWaiting() == 2 ? "都到齊了,繼續前進" : "正在等候");
cb.await();
} catch (Exception e) { e.printStackTrace(); }
});
}
service.shutdown();
}
}
| 特性 | Semaphore | CyclicBarrier |
|---|---|---|
| 核心目的 | 限制同時訪問資源的線程數 | 讓多線程在屏障點同步會合 |
| 同步方向 | 單向(獲取→釋放) | 雙向(所有線程互相等待) |
| 可重用性 | 永久可用 | 循環可用(await 後自動重置) |
| 典型場景 | 連接池、限流、資源隔離 | 分階段任務、並行計算同步 |
| 公平性選項 | 支持公平/非公平 | 無公平性選項 |
tryAcquire(timeout) 超時獲取、availablePermits() 監控剩餘許可、drainPermits() 獲取並清空所有許可getNumberWaiting() 獲取當前等待線程數、isBroken() 檢查是否損壞(線程中斷/超時導致)、reset() 重置屏障CountDownLatch 一次性、不可重置;CyclicBarrier 可循環使用SemaphoreCyclicBarrierfinally 塊中 release(),防止許可洩漏