定義
Semaphore :信號量,併發控制中用於控制某個資源同時被訪問的個數。例如程序中某個方法執行耗時長,所需資源量大。可以通過Semaphore控制同一時刻訪問該方法的線程數。
應用場景
主要用於流量控制,特別是公共資源有限
的的應用場景(數據庫連接)或者一些慢服務
。
主要方法
- public Semaphore(int permits) :構造函數一,permits爲信號量許可證的大小;
- public Semaphore(int permits, boolean fair) :構造函數二:fair爲是否設置公平策略參數,如果爲true,申請許可證的等待線程會進入FIFO隊列中。若爲false,允許等待的線程有插隊的可能。
- public void acquire():以阻塞的方式獲取一個申請許可證,在有可用的許可證時候就返回許可;如果沒有可用的許可則阻塞等待,直至獲取到許可;
- public void acquire(int permits):同時獲取permits個許可;
- public void release():釋放一個許可;
- public void acquire(int permits):釋放permits個許可;
- public boolean tryAcquire():嘗試獲取許可證,如果當前沒有可用的許可證,申請的線程不需要進入阻塞,而是繼續往下執行;
- public boolean tryAcquire(long timeout, TimeUnit unit) :帶有超時時間去獲取蓄許可證。例如“5秒鐘內還是獲取不到許可證,我就繼續往下執行,幹自己的事!”
- public int availablePermits():查詢可用的許可;
例子
package com.mark.learning.concurrent2.flowcontrol.semaphore;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @Description: 演示Semaphore用法
* @Author: Mark
* @CreateDate: 2020/2/3 14:15
* @Version: 1.0
* @Copyright : 豆漿油條個人非正式工作室
*/
@Slf4j
class Task implements Runnable{
private static final Semaphore SEMAPHORE = new Semaphore(3,true);
@Override
public void run() {
//獲取信號量許可證
try {
SEMAPHORE.acquire();
log.info(Thread.currentThread().getName()+"獲取到了 信號量許可證");
} catch (InterruptedException e) {
e.printStackTrace();
}
//模擬 耗時長的程序
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//釋放信號量
SEMAPHORE.release();
log.info(Thread.currentThread().getName()+"釋放了 信號量許可證");
}
}
public class SemaphoreDemo1 {
private static ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
//運行十個線程
for (int i = 0; i < 10; i++) {
executorService.execute(new Task());
}
executorService.shutdown();
}
}
運行結果
16:39:57.795 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:39:57.795 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2獲取到了 信號量許可證
16:39:57.795 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證
16:40:02.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4獲取到了 信號量許可證
16:40:02.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5釋放了 信號量許可證
16:40:02.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2釋放了 信號量許可證
16:40:02.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4釋放了 信號量許可證
16:40:07.801 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證
16:40:07.801 [pool-1-thread-3] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-3釋放了 信號量許可證
16:40:07.801 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5獲取到了 信號量許可證
16:40:07.801 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2獲取到了 信號量許可證
16:40:12.802 [pool-1-thread-2] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-2釋放了 信號量許可證
16:40:12.802 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1獲取到了 信號量許可證
16:40:12.802 [pool-1-thread-5] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-5釋放了 信號量許可證
16:40:12.802 [pool-1-thread-4] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-4釋放了 信號量許可證
16:40:17.803 [pool-1-thread-1] INFO com.mark.learning.concurrent2.flowcontrol.semaphore.Task - pool-1-thread-1釋放了 信號量許可證
通過分析log的打印時間,每次最多隻能允許3個線程同時執行。
注意點
- 一次獲取可獲取和釋放多個許可證。
semaphore.acquire(3);//一次獲取三個許可
semaphore.release(3);//一次釋放三個許可
- 獲取許可和釋放許可的數量需要保持一致;
- 釋放許可不一定由獲取的許可來完成。例如線程A獲取了許可,也可以由線程B來釋放許可