synchronized 和 ReentrantLock 都是一次只允許一個線程訪問某個資源,Semaphore(信號量)可以
指定多個線程同時訪問某個資源。
示例代碼如下:
/**
* @Description: 需要一次性拿一個許可的情況
*/
public class SemaphoreExample1 {
// 請求的數(shù)量
private static final int threadCount = 550;
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建一個具有固定線程數(shù)量的線程池對象(如果這里線程池的線程數(shù)量太少的話你會發(fā)現(xiàn)執(zhí)行得很
慢)
ExecutorService threadPool = Executors.newFixedThreadPool(300);
// 一次只能允許執(zhí)行一次線程數(shù)量。
final Semaphore semaphore = new Semaphore(20);
for (int i = 0; i < threadCount; i++) {
final int threadnum = i;
threadPool.execute(() -> {// Lambda 表達(dá)式的運(yùn)用
try {
semaphore.acquire();// 獲取一個許可,所以可運(yùn)行線程數(shù)量為20/1=20test(threadnum);
semaphore.release();// 釋放一個許可
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
threadPool.shutdown();
System.out.println(“finish”);
}
public static void test(int threadnum) throws InterruptedException {
Thread.sleep(1000);// 模擬請求的耗時操作
System.out.println(“threadnum:” + threadnum);
Thread.sleep(1000);// 模擬請求的耗時操作
}
}
執(zhí)行 acquire 方法阻塞,直到有一個許可證可以獲得然后拿走一個許可證;每個 release 方法增加一個許可證,這可能會釋放一個阻塞的信息 acquire 方法。然而,其實并沒有實際的許可證這個對象,Semaphore 只是維持了一個可獲得許可證的數(shù)量。 Semaphore 經(jīng)常用于限制獲取某種資源的線程數(shù)量。
當(dāng)然一次也可以一次拿取和釋放多個許可,不過一般沒有必要這樣做:
semaphore.acquire(5);// 獲取5個許可,所以可運(yùn)行線程數(shù)量為20/5=4
test(threadnum);semaphore.release(5);// 獲取5個許可,所以可運(yùn)行線程數(shù)量為20/5=4
除了 acquire 方法之外,另一個比較常用的與之對應(yīng)的方法是 tryAcquire 方法,該方法如果獲取不到許可就立即返回 false。Semaphore 有兩種模式,公平模式和非公平模式。
公平模式: 調(diào)用 acquire 的順序就是獲取許可證的順序,遵循 FIFO;
非公平模式: 搶占式的。
Semaphore 對應(yīng)的兩個構(gòu)造方法如下:
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
這兩個構(gòu)造方法,都必須提供許可的數(shù)量,第二個構(gòu)造方法可以指定是公平模式還是非公平模式,默認(rèn)非公平模式。
【關(guān)注】轉(zhuǎn)發(fā)了解更多內(nèi)容,方便后續(xù)查看