簡介
Semaphore信号量計數器。和CountDownLatch,CyclicBarrier類似,是多線程協作的工具類,相對于join,wait,notify方法使用起來簡單高效。下面我們主要看看它的用法吧!
實戰
- 限流。限制線程的并發數。
比如在一個系統中同時隻能保證5個使用者同時線上。
import java.util.concurrent.Semaphore;
/**
* @author :jiaolian
* @date :Created in 2021-03-04 11:13
* @description:Semaphore限流
* @modified By:
* 公衆号:叫練
*/
public class LimitCurrnet {
public static void main(String[] args) throws InterruptedException {
//定義20個線程,每次最多隻能執行5個線程;
Semaphore semaphore = new Semaphore(5);
for (int i=0; i<20; i++) {
new Thread(()->{
try {
//擷取憑證
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"登入成功");
Thread.sleep(2000);
//釋放憑證
semaphore.release();
System.out.println(Thread.currentThread().getName()+"使用者退出");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
如上代碼所示:我們定義了20個使用者同時通路系統,Semaphore參數是5,表示同時隻能有5個使用者可以擷取憑證,其他使用者必須等待直到有線上使用者退出。調用semaphore.acquire()表示擷取憑證,此時憑證數會減一,調用semaphore.release()表示釋放憑證,憑證數會加一,如果系統中有等待的使用者,操作此方法會通知等待的一個使用者擷取憑證成功,執行登入操作。最後列印部分結果如下:證明系統最多能保持5個使用者同時線上。
注意:上面舉出的這個案例,出個思考題:線程池是否可以實作呢?
- 模拟CyclicBarrier,CountDownLatch重用!
Semaphore可以輕松實作CountDownLatch計數器,CyclicBarrier回環屏障,還記得CountDownLatch用法麼?它是個計數器,可以幫我們統計線程執行時間,常用來測試多線程高并發執行接口效率,我們下面用Semaphore模拟多線程主線程等待子線程執行完畢再傳回。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @author :jiaolian
* @date :Created in 2021-03-01 21:04
* @description:信号量測試
* @modified By:
* 公衆号:叫練
*/
public class SemaphoreTest {
//定義線程數量;
private static final int THREAD_COUNT = 2;
//初始化信号量為0,預設是非公平鎖
private static Semaphore semaphore = new Semaphore(0,false);
private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
public static void main(String[] args) throws InterruptedException {
for (int i=0; i<THREAD_COUNT; i++) {
executorService.submit(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"執行");
semaphore.release();
});
}
//擷取2個信号量
semaphore.acquire(2);
System.out.println("主線程執行完畢");
executorService.shutdown();
}
}
如上代碼所示:我們定義了Semaphore初始化信号量為0,預設是非公平鎖,在主線程中用線程池送出2個線程,主線程調用semaphore.acquire(2)表示需要擷取兩個信号量,但此時初始化信号量為0,此時AQS中的state會是0-2=-2,state值小于0,是以主線程執行這句話會阻塞将其加入AQS同步隊列,線程池兩個線程等待2秒後會調用semaphore.release()釋放2個信号量,此時AQS中的state會自增到0,會通知主線程退出等待繼續往下執行。執行結果如下圖所示。
有沒有發現Semaphore用法可以模拟CountDownLatch,另外Semaphore通過調用acquire,release方法,還可以實作CyclicBarrier功能!我們不舉例了。
實作原理
- 相同點:本質上都是計數器,底層是依賴AQS操作state實作。
- 異同點:CountDownLatch是共享鎖實作,CyclicBarrier是獨占鎖實作,CountDownLatch通過調用countDown遞減計數器隻能使用一次,而CyclicBarrier通過調用await遞減計數器可以達到“回環”重複的效果。Semaphore也是共享鎖實作,通過調用release計數器是遞增的,通過設定信号量可以實作CyclicBarrier,CountDownLatch功能。
總結
今天我們介紹了Semaphore,整理出來希望能對你有幫助,寫的比不全,同時還有許多需要修正的地方,希望親們加以指正和點評,喜歡的請點贊加關注哦。點關注,不迷路,我是【叫練】公衆号,微信号【jiaolian123abc】邊叫邊練。