首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 信號量 Semaphore 詳解:資源池控制、公平鎖、超時獲取實戰

     編輯:Java 相關知識

Semaphore (信號量) 維護一組**許可證**,執行緒 acquire() 取得許可、release() 歸還。核心用途:**限流**、資源池連線控制、並發任務閘門。支援公平/非公平模式、可中斷/超時獲取。

核心建構子


new Semaphore(int permits)                    // 非公平 (預設)
new Semaphore(int permits, boolean fair)      // true = 公平 (FIFO)

關鍵 API

方法行為拋出
acquire()阻塞直到取得 1 張許可InterruptedException
acquire(int permits)阻塞直到取得 N 張許可InterruptedException
tryAcquire()立即嘗試,成功 true/失敗 false無
tryAcquire(timeout, unit)超時等待InterruptedException
release() / release(int)歸還許可,喚醒等待執行緒無
availablePermits()當前可用許可數 (近似值)無
drainPermits()強制取走所有許可,回傳數量無

完整範例:模擬 2 個停車位,10 輛車搶車位


import java.util.concurrent.*;

public class SemaphoreParking {
    static class Car extends Thread {
        private final int id;
        private final Semaphore semaphore;
        Car(int id, Semaphore semaphore) { this.id = id; this.semaphore = semaphore; }

        @Override public void run() {
            boolean got = false;
            try {
                System.out.printf("Car %d 到達,可用車位: %d%n", id, semaphore.availablePermits());
                semaphore.acquire(); // 佔車位
                got = true;
                System.out.printf("Car %d 佔車位%n", id);
                Thread.sleep((long) (Math.random() * 3000)); // 停車 0-3 秒
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                if (got) {
                    System.out.printf("Car %d 離開%n", id);
                    semaphore.release(); // 釋放車位
                }
            }
        }
    }

    public static void main(String[] args) {
        Semaphore parking = new Semaphore(2, true); // 2 車位,公平模式
        ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 1; i <= 10; i++) es.execute(new Car(i, parking));
        es.shutdown();
    }
}

執行片段


Car 1 到達,可用車位: 2
Car 2 到達,可用車位: 2
Car 1 佔車位
Car 2 佔車位
Car 3 到達,可用車位: 0
Car 4 到達,可用車位: 0
...
Car 1 離開
Car 3 佔車位    ← 公平模式下,等待最久的優先

進階模式

1. 計數器式限流 (每秒最多 N 次)


Semaphore rateLimiter = new Semaphore(100); // 每秒 100 次
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
    rateLimiter.release(100); // 每秒補滿
    // 多餘許可會累積,可用 drainPermits() 重置
}, 1, 1, TimeUnit.SECONDS);

// 業務呼叫
if (rateLimiter.tryAcquire()) { doWork(); } else { reject(); }

2. 階段式啟動同步 (替代 CountDownLatch 可重用)


Semaphore startGate = new Semaphore(0);
// 初始化線程完成後
startGate.release(N); // 釋放 N 張許可,喚醒 N 個工作線程
// 工作線程
startGate.acquire(); // 等待啟動信號
doWork();

Semaphore vs CountDownLatch vs CyclicBarrier

特性SemaphoreCountDownLatchCyclicBarrier
核心概念許可證池倒數計數器攔截屏障
可重用✅❌✅
雙向同步❌❌✅ (所有方到達才放行)
典型場景資源池、限流啟動等待、一次性聚合多階段並行、迭代同步

最佳實務

  • 公平模式:高爭用時減少飢餓,但吞吐略低;低爭用用非公平 (預設) 效能更好。
  • 釋放許可不需持有:release() 可由任何執行緒呼叫,不必是 acquire() 的同一執行緒。
  • 避免許可洩漏:acquire() 後務必在 finally 中 release(),否則許可永久流失導致死鎖。
  • 監控:getQueueLength() (等待執行緒數)、hasQueuedThreads() 納入指標監控。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved