1、Semaphore 的作用
一種計數信號量。通常用於限制能夠訪問某系資源的線程數。
維護一組許可證,每個 acquire 將獲取一個許可證,每個 release 會釋放一個許可證。
2、核心結構
//所有機制通過AbstractQueuedSynchronizer子類實現
private final Sync sync;
3、構造方法
// 默認不考慮公平策略
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
// fair=true,考慮公平策略
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
4、實例測試
/**
*
* Semaphore用法實例(來自JDK1.8 Semaphore).
* 同一時間只能最多只能有五個工作者同時進行工作。
*
* @version 1.0
*/
public class SemaphoreDriverDemo {
public static void main(String[] args) {
SemaphorePool semaphorePool = new SemaphorePool();
for (int i = 0; i < 20; i++) {
SemaphoreWorker semaphoreWorker = new SemaphoreWorker(semaphorePool);
semaphoreWorker.setName("工作者" + i);
semaphoreWorker.start();
}
}
}
class SemaphoreWorker extends Thread {
private SemaphorePool semaphorePool;
public SemaphoreWorker(SemaphorePool semaphorePool) {
this.semaphorePool = semaphorePool;
}
public void run() {
try {
/**
* 獲取一個許可,最多獲取5個許可
*/
Object object = semaphorePool.getItem();
System.out.println(Thread.currentThread().getName() + ":開始工作-----當前時間:" + getFormatTimeStr());
TimeUnit.SECONDS.sleep(2);
/**
* 釋放一個許可
* 如果不釋放,那麼其他線程無法獲取許可將無法進行工作
*/
semaphorePool.putItem(object);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static String getFormatTimeStr() {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return sf.format(new Date());
}
}
/**
*
* 使用信號量來控制對一個池的訪問
*
* @version 1.0
*/
class SemaphorePool {
private static final int MAX_AVAILABLE = 5;
private final Semaphore available = new Semaphore(5, true);
/**
*
* 方法描述:獲取一個許可
*
* @return
* @throws InterruptedException
*
*/
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailAbleItem();
}
/**
*
* 方法描述:釋放一個許可
*
* @param x
*
*/
public void putItem(Object x) {
if (markAsUnused(x)) {
available.release();
}
}
protected Object[] items = { "object_1", "object_2", "object_3", "object_4", "object_5" };
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailAbleItem() {
for (int i = 0; i < MAX_AVAILABLE; i++) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null;
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; i++) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else {
return false;
}
}
}
return false;
}
}