文字摘抄於:https://yq.aliyun.com/articles/632589
Semaphore(信號量)是用來控制同時訪問特定資源的線程數量,它通過協調各個線程,以保證合理的使用公共資源。換句話說,鎖(Lock鎖或synchronized鎖)在任何時刻只允許一個任務訪問被加鎖的資源,而計數信號量允許n個任務同時訪問這個資源,還可以將信號量看作是向外分發使用資源的“許可證”,儘管內部沒有這種許可證對象。
“許可證”的數量是有限的,所以當執有“許可證”的線程數量與“許可證”數量相同時,就會阻止其他線程對共享資源的使用,如果某一個或多個線程使用完共享資源後,就會歸還“許可證”,此時Semaphore(信號量)就會將這些歸還的“許可證”再次分發給阻塞中的線程。通過這種方式就實現了控制線程併發數。
應用:
Semaphore可以用於做流量控制,特別是公用資源有限的應用場景,比如數據庫連接。假如有一個需求,要讀取幾萬個文件的數據,因爲都是IO密集型任務,我們可以啓動幾十個線程 併發地讀取,但是如果讀到內存後,還需要存儲到數據庫中,而數據庫的連接數只有10個,這 時我們必須控制只有10個線程同時獲取數據庫連接保存數據,否則會報錯無法獲取數據庫連 接。這個時候,就可以使用Semaphore來做流量控制。
代碼
public static void main(String[] args) throws InterruptedException {
// 同一時間,允許最大線程數量獲取
final MySemaphore semaphore = new MySemaphore(1);
for(int i = 0; i<2; i++ )
new Thread(() -> {
try {
// 獲取信號量
semaphore.acquire();
//boolean b = semaphore.tryAcquire(); 嘗試去拿,這個方法有入參
// semaphore.drainPermits(); // 獲取所有的許可證
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 釋放
semaphore.release();
}
}).start();
while(true){
System.out.println("AP: " + semaphore.availablePermits()); // 當前可用的信號量
System.out.println("QL: " + semaphore.getQueueLength()); // 阻塞的信號量
semaphore.hasQueuedThreads(); // 是否有等待線程
Collection<Thread> queuedThreads = semaphore.getQueuedThreads(); // 在等待的線程隊列
TimeUnit.SECONDS.sleep(1);
}
}
static class MySemaphore extends Semaphore{
public MySemaphore(int permits) {
super(permits);
}
public MySemaphore(int permits, boolean fair) {
super(permits, fair);
}
@Override
protected Collection<Thread> getQueuedThreads() {
return super.getQueuedThreads();
}
}