併發工具類系列:
定義
計數訊號量用來控制同時訪問某個特定資源的運算元量,或者同時執行某個指定操作的數量。訊號量還可以用來實現某種資源池,或者對容器施加邊界。
Semaphore管理著一組許可(permit),許可的初始數量可以通過建構函式設定,操作時首先要獲取到許可,才能進行操作,操作完成後需要釋放許可。如果沒有獲取許可,則阻塞到有許可被釋放。如果初始化了一個許可為1
的Semaphore,那麼就相當於一個不可重入的互斥鎖(Mutex)。
例項場景
理論的聽起來有些繞口,其實假設生活中一個常見的場景:每天早上,大家都熱衷於帶薪上廁所,但是公司廁所一共只有10
個坑位。。那麼只能同時10
個人用著,後面來的人都得等著(阻塞),如果走了2
個人,那麼又可以進去2
個人。這裡面就是Semaphore的應用場景,爭奪有限的資源。
程式碼實戰
package concurrency;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
class Employee implements Runnable {
private String id;
private Semaphore semaphore;
private static Random rand= new Random(47);
public Employee(String id, Semaphore semaphore) {
this.id = id;
this.semaphore = semaphore;
}
public void run() {
try {
semaphore.acquire();
System.out.println(this.id + "is using the toilet");
TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
semaphore.release();
System.out.println(this.id + "is leaving");
} catch (InterruptedException e) {
}
}
}
public class ToiletRace {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool = Executors
.newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(10);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new Employee(String.valueOf(i), s));
}
threadPool.shutdown();
}
}
複製程式碼
這裡我定義了30個人要上廁所,但是隻有10個坑位,每個人消耗隨機的時間,直接執行上面這段程式碼,可以看到一開始進去了10個人,後來就是陸陸續續的有人進,有人出了。但是正在使用的一定不會超過10個的。
Semaphore是很好用的Java併發工具,除了上面這個例子,我們在工作中經常用它管理資料庫連線或者保護其它受限資源的併發使用。當然Semaphore還有其它的一些方法,可以檢視剩餘的許可數,可以檢視正在使用許可的執行緒數,具體使用時可以檢視官方文件。