天天看點

Semaphore實戰

簡介

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個使用者同時線上。

Semaphore實戰

注意:上面舉出的這個案例,出個思考題:線程池是否可以實作呢?

  • 模拟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實戰

有沒有發現Semaphore用法可以模拟CountDownLatch,另外Semaphore通過調用acquire,release方法,還可以實作CyclicBarrier功能!我們不舉例了。

實作原理

  • 相同點:本質上都是計數器,底層是依賴AQS操作state實作。
  • 異同點:CountDownLatch是共享鎖實作,CyclicBarrier是獨占鎖實作,CountDownLatch通過調用countDown遞減計數器隻能使用一次,而CyclicBarrier通過調用await遞減計數器可以達到“回環”重複的效果。Semaphore也是共享鎖實作,通過調用release計數器是遞增的,通過設定信号量可以實作CyclicBarrier,CountDownLatch功能。

總結

今天我們介紹了Semaphore,整理出來希望能對你有幫助,寫的比不全,同時還有許多需要修正的地方,希望親們加以指正和點評,喜歡的請點贊加關注哦。點關注,不迷路,我是【叫練】公衆号,微信号【jiaolian123abc】邊叫邊練。