如何用訊號量去實現一個限流器?
- 2022 年 3 月 27 日
- 筆記
- Java並發編程實戰
1)什麼是訊號量呢?
-
65年斯特拉提出來訊號量,一直用到80年左右都是用它來解決並發的問題,直到管程模型出來了,他就逐漸落魄了。訊號量你可以類比生活中的紅綠燈,綠燈行紅燈停。
2)訊號量模型是怎樣的?
-
一個計數器,一個等待隊列,3個方法(init(),up(),dowm())
3)訊號量的工作原理是什麼?
-
當執行緒進臨界資源的時候,先把count-1,然後看是不是<0的,如果<0那麼對不起,不能進入 ,老老實實進等待隊列去。如果>=0,那麼可以進入,出來的時候把count+1,當count>=0了,那麼就去喚醒等待隊列的一個執行緒。
4)有了管程了,那訊號量還有存在的意義嗎?
-
有,訊號量他有自己的不可替代性,他允許多個執行緒進入臨界資源,這個對我們的池化技術實現是有很大幫助的,比如我們的資料庫連接池,對象池。
5)如何用訊號量快速實現一個限流器?
-
比如現在我們的需求是10個執行緒為上限,超過10個就限制進入。那我可以這樣設計,count初始化為10,那麼我10個執行緒拿到count的時候,都是>=0的,第11個執行緒來的時候,把count-1,count=-1小於0了,所以進等待隊列去。
class ObjPool<T, R> {
final List<T> pool;
// 用訊號量實現限流器
final Semaphore sem;
// 構造函數
ObjPool(int size, T t){
pool = new Vector<T>(){};
for(int i=0; i<size; i++){
pool.add(t);
}
sem = new Semaphore(size);
}
// 利用對象池的對象,調用func
R exec(Function<T,R> func) {
T t = null;
sem.acquire();
try {
t = pool.remove(0);
return func.apply(t);
} finally {
pool.add(t);
sem.release();
}
}
}
// 創建對象池
ObjPool<Long, String> pool =
new ObjPool<Long, String>(10, 2);
// 通過對象池獲取t,之後執行
pool.exec(t -> {
System.out.println(t);
return t.toString();
});
6)思考一下,上面的限流器使用的是vector來做對象集合的,那可不可以用ArrayList呢?