# Semaphore信号量

- Semaphore 可以用來限制或管理數量有限資源的使用情況
- 信号量的作用是用來維護一個“許可證”,的計數,線程可以擷取 許可證,那信号量剩餘許可證就減一,線程也可以是否一個許可證,那剩餘的許可證就加一,當信号量擁有的許可證為0時,那麼下一個線程想獲得許可證,就要進行等待,直到另外線程釋放許可證
信号量使用流程
: 1.初始化Semaphore 并指定許可證的數量
: 2.在需要被現在的代碼前加acquire() 或者 acquireUninterruptibly()方法
: 3.在任務結束後,調用release() 來釋放許可證
信号量主要方法使用
: 1.new Semaphore(int permits,boolean fair): 這裡可以設定是否使用公平政策,如果傳入true,那麼Semaphore 會把之前等待的線程放到FIFO的隊列裡,以便于當有了新的許可證,可以分發給之前等了最長時間的線程
: 2.tryAcquire() : 看看現在有沒有空閑的許可證,如果有的話就擷取,如果沒有的話也沒關系,我不必陷入阻塞,我可以i去做别的事情,過一會再來檢視許可證的空閑情況
: 3.tryAcquire(timeout) : 和tryAcquire()一樣,但是多了逾時時間,比如 “在3秒内擷取不到許可證,我去做别的事情”
- 代碼示範
package com.yxl.task;
import lombok.SneakyThrows;
import org.omg.PortableInterceptor.INACTIVE;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.*;
/**
* Semaphore 示範demo
*/
public class SemaphoreDemo {
static Semaphore semaphore =new Semaphore(3,true);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(50);
for (int i = 0; i < 50; i++) {
executorService.execute(new Task());
}
executorService.shutdown();
}
static class Task implements Runnable{
@SneakyThrows
@Override
public void run() {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"拿到來許可證");
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+"釋放了許可證");
semaphore.release();
}
}
}
運作結果,會發現他是3個那到,三個釋放 執行線程
我們修改擷取信号量到參數
@SneakyThrows
@Override
public void run() {
semaphore.acquire(3);
System.out.println(Thread.currentThread().getName()+"拿到來許可證");
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+"釋放了許可證");
semaphore.release(3);
}
每次運作一個線程都會拿到3個許可證
- 可以根據我們到需求一次擷取或者釋放多個許可證
- 比如TaskA會調用很消耗資源到 method1() 而TaskB 調用到是不太消耗資源到 mehod2(), 假設我們一共有5個許可證,那麼我們就可以要求TaskA 擷取5個許可證才能執行,這樣避免了A B 同時運作到情況,我們可以根據直接到需求和裡配置設定資源
注意點
: 1.擷取和釋放到許可證數量必須一緻,否則比如每次都擷取2個但是隻釋放一個甚至不釋放,随着時間到推移,到最後許可證數量不夠用,會導緻程式卡死。
: 2.注意在初始化Semaphore的時候設定公平性,一般設定為 true 更合理
: 3.信号量的作用,除了控制臨界區最多同時有N個線程通路外,林一個作用是可以實作“條件等待”,例如 線程1需要線上程2完成準備工作後才能開始工作,那麼線程1 acquire() , 而線程2完成任務後release(),這樣電話,相當于輕量級的CountDownLatch
個人部落格位址:
http://blog.yanxiaolong.cn/