一、什麼是訊號量
“訊號量”在程式設計術語中使用單詞semaphore,那什麼是“訊號量”?訊號量就好比你家廚房入口架子上擺了三把鍋。
- 如果你的孩子熱奶拿走一把,你的老婆熱湯拿走一把,你的媽媽做菜拿走一把,你想煮麵條就沒有鍋了。當你看到這種情況,你就不會進入廚房了,你處於等待狀態。也就說廚房按照“鍋的數量”作為訊號量,只能容納三個人(執行緒)。
- 當你的老婆熱完湯之後,把鍋重新放回架子上,你就可以去獲得一個鍋,你就可以進入廚房了。
二、訊號量類Semaphore
通過上文的介紹,我們可以總結出訊號量的重要組成部分
- 計數器:計算訊號量的使用情況,鍋(訊號)被使用一次減1,鍋(訊號)被還回一次加1
- 等待佇列:當任務數量大於訊號量數量上限的時候,任務進入等待佇列
訊號量在JDK中是由 java.util.concurrent.Semaphore 實現的,Semaphore提供了兩個建構函式。permits引數代表訊號量的數量(鍋的數量),fair代表訊號量的獲取是否遵循公平原則。所謂的公平原則就是:先啟動的執行緒先呼叫semaphore.acquire();
方法,就先得到一個訊號“鍋”(permit),遵循先來後到的原則。
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
常用方法列表
方法名 | 作用 |
---|---|
acquire() | 獲取一個permit,在獲取到permit之前,執行緒處於阻塞狀態 |
tryAcquire() | 嘗試獲取一個permit,獲取成功返回true,否則返回false,不阻塞執行緒 |
tryAcquire(long timeout, TimeUnit unit) | 和tryAcquire()大部分實現一樣,區別是提供超時設定,在超時時間範圍內多次嘗試,不阻塞執行緒。 |
availablePermits() | 獲取目前剩餘的訊號permit的數量 |
release() | 釋放一個permit,並喚醒一個等待訊號permit的執行緒 |
hasQueuedThreads() | 返回值boolean型別,判斷等待佇列中是否存在等待執行緒 |
getQueueLength() | 獲取等待佇列中等待執行緒的數量 |
三、實現限流器
通過上面的介紹,我相信大家肯定可以想到Semaphore的應用場景。比如:
- 醫院門診排號器,三個在崗醫生就是3個訊號permit,當超出訊號量數量的時候,想就診就只能等待
- 停車場停車功能,n個車位就是n個訊號permit,當超出訊號量數量的時候,想停車也只能等待
應用場景還有很多很多,大家自己去發會創造力吧。其實無論多少種應用場景說白了:Semaphore實現的就是一個限流器。我們還是以我們家的廚房kitchen裡面的三把鍋wok為例,實現基於訊號量的限流。
public class TestKitchenSemaphore {
//訊號量-3把鍋
private static Semaphore threeWoks = new Semaphore(3);
public static void main(String[] args) throws InterruptedException {
//模擬5個人搶佔3把鍋的場景
for(int i=0;i < 5;i++){
Thread.sleep(1000); //模擬進入廚房的先後順序,存在時間間隔
new Thread(() -> {
try {
threeWoks.acquire(); //獲取一個permit,訊號量計數器減1
System.out.println(Thread.currentThread().getName()
+ "拿走了一把鍋,還剩" + threeWoks.availablePermits() + "把鍋");
Thread.sleep(new Random().nextInt(5000)); //模擬使用鍋的時長
threeWoks.release();//釋放permit,訊號量計數器加1
System.out.println(Thread.currentThread().getName()
+ "還回一把鍋,還剩" + threeWoks.availablePermits() + "把鍋");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
上文程式碼的輸出如下,我們可以看到每acquire一次訊號量減1,每release一次訊號量加1。訊號量的上限是3,下限是0。當達到上限的時候,只有等先佔據鍋permit的執行緒釋放,其他執行緒才能獲取到鍋permit。
Thread-0拿走了一把鍋,還剩2把鍋
Thread-1拿走了一把鍋,還剩1把鍋
Thread-2拿走了一把鍋,還剩0把鍋 => 備註:5個執行緒只能獲取3個鍋(上限)
Thread-1還回一把鍋,還剩1把鍋
Thread-3拿走了一把鍋,還剩0把鍋 => 備註:被還回才能被再次佔用,不超過3
Thread-0還回一把鍋,還剩1把鍋
Thread-4拿走了一把鍋,還剩0把鍋 => 備註:被還回才能被再次佔用,不超過3
Thread-2還回一把鍋,還剩1把鍋
Thread-3還回一把鍋,還剩2把鍋
Thread-4還回一把鍋,還剩3把鍋 => 備註:用完依次釋放
歡迎關注我的部落格,更多精品知識合集
本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格 - zimug.com
覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力!。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。