允許多個執行緒同時訪問的Semaphore(訊號量)
阿新 • • 發佈:2021-01-01
synchronized 和 ReentrantLock 都是一次只允許一個執行緒訪問某個資源,Semaphore(訊號量)可以指定多個執行緒同時訪問某個資源。
示例程式碼如下:
/** * * @author Snailclimb * @date 2018年9月30日 * @Description: 需要一次性拿一個許可的情況 */ public class SemaphoreExample1 { // 請求的數量 private static final int threadCount = 550; public static void main(String[] args) throws InterruptedException { // 建立一個具有固定執行緒數量的執行緒池物件(如果這裡執行緒池的執行緒數量給太少的話你會發現執行的很 慢) ExecutorService threadPool = Executors.newFixedThreadPool(300); // 一次只能允許執行的執行緒數量。 final Semaphore semaphore = new Semaphore(20); for (int i = 0; i < threadCount; i++) { final int threadnum = i; threadPool.execute(() -> {// Lambda 表示式的運用 try { semaphore.acquire();// 獲取一個許可,所以可執行執行緒數量為20/1=20 test(threadnum); semaphore.release();// 釋放一個許可 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }); } threadPool.shutdown(); System.out.println("finish"); } public static void test(int threadnum) throws InterruptedException { Thread.sleep(1000);// 模擬請求的耗時操作 System.out.println("threadnum:" + threadnum); Thread.sleep(1000);// 模擬請求的耗時操作 } }
執行 acquire 方法阻塞,直到有一個許可證可以獲得然後拿走一個許可證;每個 release 方法增加一個許可證,這可能會釋放一個阻塞的 acquire 方法。然而,其實並沒有實際的許可證這個物件,Semaphore 只是維持了一個可獲得許可證的數量。 Semaphore 經常用於限制獲取某種資源的執行緒數量。
當然一次也可以一次拿取和釋放多個許可,不過一般沒有必要這樣做:
semaphore.acquire(5);// 獲取5個許可,所以可執行執行緒數量為20/5=4 test(threadnum); semaphore.release(5);// 獲取5個許可,所以可執行執行緒數量為20/5=4
除了 acquire 方法之外,另一個比較常用的與之對應的方法是 tryAcquire 方法,該方法如果獲取不到許可就立即返回 false。
Semaphore 有兩種模式,公平模式和非公平模式。
公平模式: 呼叫 acquire 的順序就是獲取許可證的順序,遵循 FIFO;
非公平模式: 搶佔式的。
Semaphore 對應的兩個構造方法如下:
public Semaphore(int permits) { sync = new NonfairSync(permits); } public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }
這兩個構造方法,都必須提供許可的數量,第二個構造方法可以指定是公平模式還是非公平模式,預設非公平模式。
補充:Semaphore與CountDownLatch一樣,也是共享鎖的一種實現。它預設構造AQS的state為permits。當執行任務的執行緒數量超出permits,那麼多餘的執行緒將會被放入阻塞佇列Park,並自旋判斷state是否大於0。只有當state大於0的時候,阻塞的執行緒才能繼續執行,此時先前執行任務的執行緒繼續執行release方法,release方法使得state的變數會加1,那麼自旋的執行緒便會判斷成功。
如此,每次只有最多不超過permits數量的執行緒能自旋成功,便限制了執行任務執行緒的數量。
以上就是本期更新內容,關注下期更精彩哦!