1. 程式人生 > 其它 >CounDownLatch、CyclicBarrier、Semaphore

CounDownLatch、CyclicBarrier、Semaphore

CountDownLatch是在java1.5被引入,跟它一起被引入的工具類還有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。

CountDownLatch概念

CountDownLatch是一個同步工具類,用來協調多個執行緒之間的同步,或者說起到執行緒之間的通訊(而不是用作互斥的作用)。

CountDownLatch能夠使一個執行緒在等待另外一些執行緒完成各自工作之後,再繼續執行。使用一個計數器進行實現。計數器初始值為執行緒的數量。當每一個執行緒完成自己任務後,計數器的值就會減一。當計數器的值為0時,表示所有的執行緒都已經完成一些任務,然後在CountDownLatch上等待的執行緒就可以恢復執行接下來的任務。

CountDownLatch的用法

CountDownLatch典型用法:1、某一執行緒在開始執行前等待n個執行緒執行完畢。將CountDownLatch的計數器初始化為new CountDownLatch(n),每當一個任務執行緒執行完畢,就將計數器減1 countdownLatch.countDown(),當計數器的值變為0時,在CountDownLatch上await()的執行緒就會被喚醒。一個典型應用場景就是啟動一個服務時,主執行緒需要等待多個元件載入完畢,之後再繼續執行。

CountDownLatch典型用法:2、實現多個執行緒開始執行任務的最大並行性。注意是並行性,不是併發,強調的是多個執行緒在某一時刻同時開始執行。類似於賽跑,將多個執行緒放到起點,等待發令槍響,然後同時開跑。做法是初始化一個共享的CountDownLatch(1),將其計算器初始化為1,多個執行緒在開始執行任務前首先countdownlatch.await(),當主執行緒呼叫countDown()時,計數器變為0,多個執行緒同時被喚醒。

// 當一個任務需要多工同時進行,提高效率,縮短序列執行時間。cdl.await最後等待位置
public static void main(String[] args) {
    CountDownLatch cdl = new CountDownLatch(3);
    ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());

    for (int i = 0; i < 3; i++) {
        executor.execute(() -> {cdl.countDown(); System.out.println(String.valueOf(1111));});
    }

    try {
        cdl.await();
        System.out.println("執行緒結束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    executor.shutdown();
}

CyclicBarrier

CyclicBarrier柵欄類似於賽跑同一起跑線
public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
        System.out.println("柵欄中的執行緒執行完成");
    });
    ExecutorService executorService = Executors.newFixedThreadPool(2);

    executorService.submit(() -> {
        try {
            cyclicBarrier.await();
            System.out.println("執行緒1:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    executorService.submit(() -> {
        try {
            cyclicBarrier.await();
            System.out.println("執行緒2:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    executorService.shutdown();
}