同步工具類(lèi)可以是任何一個(gè)對(duì)象,只要它根據(jù)其自身的狀態(tài)來(lái)協(xié)調(diào)線(xiàn)程的控制流。阻塞隊(duì)列可以作為同步工具類(lèi),其他類(lèi)型的同步工具類(lèi)還包括 信號(hào)量(Semaphore)、柵欄(CyclicBarrier)以及閉鎖(Latch)。
本文重點(diǎn)介紹Semaphore的使用以及應(yīng)用場(chǎng)景。
信號(hào)量(Semaphore)
計(jì)數(shù)信號(hào)量(Counting Semaphore)用來(lái)控制同時(shí)訪問(wèn)某個(gè)特定資源的操作數(shù)量,或者同時(shí)執(zhí)行某個(gè)指定操作的數(shù)量。
Semaphore中管理著一組虛擬的許可(permit),許可的初始數(shù)量可通過(guò)構(gòu)造函數(shù)來(lái)指定。在執(zhí)行操作時(shí)可以首先獲得許可(只要還有剩余的許可),并在使用完以后釋放許可。如果沒(méi)有許可,你們acquire方法將阻塞直到有許可(或者直到被中斷或者操作超時(shí))。release方法將返回一個(gè)許可給信號(hào)量。
Semaphore實(shí)現(xiàn)的功能就類(lèi)停車(chē)場(chǎng)有5個(gè)停車(chē)位,假如有10個(gè)人要停車(chē),那么同時(shí)只能有多少個(gè)人停車(chē)呢?同時(shí)只能有5個(gè)人能夠占用,當(dāng)5個(gè)人中的任何一個(gè)人離開(kāi)后,其中等待的另外5個(gè)人中又有一個(gè)人可以占用了。另外等待的5個(gè)人中可以是隨機(jī)獲得優(yōu)先機(jī)會(huì),也可以是按照先來(lái)后到的順序獲得機(jī)會(huì),這取決于構(gòu)造Semaphore對(duì)象時(shí)傳入的參數(shù)選項(xiàng)Semaphore(int permits, boolean fair)。
下面通過(guò)代碼來(lái)模擬停車(chē)的情形,如下:
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個(gè)線(xiàn)程同時(shí)訪問(wèn)
final Semaphore semaphore = new Semaphore(5);
// 模擬N個(gè)用戶(hù)停車(chē)
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("用戶(hù):" + id+" 獲得許可開(kāi)始停車(chē)?yán)? | "+Thread.currentThread().getName());
int time = new Random().nextInt(1000);
TimeUnit.MILLISECONDS.sleep(time);
System.out.println("當(dāng)前可用許可數(shù)量: " + semaphore.availablePermits()+" | "+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();//釋放
}
}
};
pool.execute(task);
}
pool.shutdown();
}
}