同步工具類可以是任何一個對象,只要它根據其自身的狀態來協調線程的控制流。阻塞隊列可以作為同步工具類,其他類型的同步工具類還包括 信號量(Semaphore)、柵欄(CyclicBarrier)以及閉鎖(Latch)。
本文重點介紹Semaphore的使用以及應用場景。
信號量(Semaphore)
計數信號量(Counting Semaphore)用來控制同時訪問某個特定資源的操作數量,或者同時執行某個指定操作的數量。
Semaphore中管理著一組虛擬的許可(permit),許可的初始數量可通過構造函數來指定。在執行操作時可以首先獲得許可(只要還有剩余的許可),并在使用完以后釋放許可。如果沒有許可,你們acquire方法將阻塞直到有許可(或者直到被中斷或者操作超時)。release方法將返回一個許可給信號量。
Semaphore實現的功能就類停車場有5個停車位,假如有10個人要停車,那么同時只能有多少個人停車呢?同時只能有5個人能夠占用,當5個人中的任何一個人離開后,其中等待的另外5個人中又有一個人可以占用了。另外等待的5個人中可以是隨機獲得優先機會,也可以是按照先來后到的順序獲得機會,這取決于構造Semaphore對象時傳入的參數選項Semaphore(int permits, boolean fair)
。
下面通過代碼來模擬停車的情形,如下:
package com.bytebeats.concurrent.api;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-04-24 23:22
*/
public class SemaphoreDemo {
public static void main(String[] args) {
int num = 10;
ExecutorService pool = Executors.newFixedThreadPool(num);
// 只能5個線程同時訪問
final Semaphore semaphore = new Semaphore(5);
// 模擬N個用戶停車
for (int i = 0; i < num; i++) {
final int id = i+1;
Runnable task = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire(); // 獲取許可
System.out.println("用戶:" + id+" 獲得許可開始停車啦! | "+Thread.currentThread().getName());
int time = new Random().nextInt(1000);
TimeUnit.MILLISECONDS.sleep(time);
System.out.println("當前可用許可數量: " + semaphore.availablePermits()+" | "+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();//釋放
}
}
};
pool.execute(task);
}
pool.shutdown();
}
}