CountDownLatch、CyclicBarrier、Semaphore的區別

CountDownLatch(閉鎖)

閉鎖(CountDownLatch):一種同步方法,可以延遲線程的進度直到線程到達某個終點狀態。通俗的講就是,一個閉鎖相當於一扇大門,在大門打開之前所有線程都被阻斷,一旦大門打開所有線程都將通過,但是一旦大門打開,所有線程都通過了,那麼這個閉鎖的狀態就失效了,門的狀態也就不能變了,只能是打開狀態。也就是說閉鎖的狀態是一次性的,它確保在閉鎖打開之前所有特定的活動都需要在閉鎖打開之後才能完成。

  • 應用場景:

確保某個計算在其需要的所有資源都被初始化之後才繼續執行。二元閉鎖(包括兩個狀態)可以用來表示“資源R已經被初始化”,而所有需要R的操作都必須先在這個閉鎖上等待。
確保某個服務在其依賴的所有其他服務都已經啓動之後才啓動。
等待直到某個操作的所有參與者都就緒在繼續執行。(例如:多人遊戲中需要所有玩家準備才能開始)

CountDownLatch是JDK 5+裏面閉鎖的一個實現,允許一個或者多個線程等待某個事件的發生。CountDownLatch有一個正數計數器,countDown方法對計數器做減操作,await方法等待計數器達到0。所有await的線程都會阻塞直到計數器爲0或者等待線程中斷或者超時。

有三個工人在爲老闆幹活,這個老闆有一個習慣,就是當三個工人把一天的活都幹完了的時候,他就來檢查所有工人所幹的活。記住這個條件:三個工人先全部幹完活,老闆才檢查。所以在這裏用Java代碼設計兩個類,Worker代表工人,Boss代表老闆,具體的代碼實現如下:

工人:

package lock;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author:peng
 * @date: 2018/7/26 21:02
 */
public class Work implements Runnable {

    private CountDownLatch downLatch;
    private String name;

    public Work(CountDownLatch downLatch, String name) {
        this.downLatch = downLatch;
        this.name = name;
    }

    public void run() {
        this.doWork();
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException ie) {
        }
        System.out.println(this.name + "活幹完了!");
        this.downLatch.countDown();

    }

    private void doWork() {
        System.out.println(this.name + "正在幹活!");
    }

}

老闆:

package lock;

import java.util.concurrent.CountDownLatch;

/**
 * @author:peng
 * @date: 2018/7/26 21:03
 */
public class Boss implements Runnable {
    private CountDownLatch downLatch;

    public Boss(CountDownLatch downLatch) {
        this.downLatch = downLatch;
    }

    public void run() {
        System.out.println("老闆正在等所有的工人幹完活......");
        try {
            this.downLatch.await();
        } catch (InterruptedException e) {
        }
        System.out.println("工人活都幹完了,老闆開始檢查了!");
    }


}

測試代碼:

package lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 閉鎖測試用例
 *
 * @author:peng
 * @date: 2018/7/26 21:03
 */
public class CountDownLatchTest {


    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        CountDownLatch latch = new CountDownLatch(3);

        Work w1 = new Work(latch,"張三");
        Work w2 = new Work(latch,"李四");
        Work w3 = new Work(latch,"王二");

        Boss boss = new Boss(latch);

        executor.execute(w3);
        executor.execute(w2);
        executor.execute(w1);
        executor.execute(boss);

        executor.shutdown();
    }

}

執行結果:

李四正在幹活!
老闆正在等所有的工人幹完活......
王二正在幹活!
張三正在幹活!
李四活幹完了!
王二活幹完了!
張三活幹完了!
工人活都幹完了,老闆開始檢查了!

CyclicBarrier(柵欄)

柵欄類似於閉鎖,它能阻塞一組線程直到某個事件發生。 柵欄與閉鎖的關鍵區別在於,所有的線程必須同時到達柵欄位置,才能繼續執行。閉鎖用於等待事件,而柵欄用於等待其他線程。
場景: 應用一些協議,比如幾個家庭成員決定在某個地方集合,所有人在6:00在某地集合,到了以後要等待其他人,之後才能討論去哪裏吃飯。 並行迭代,將一個問題分成很多子問題,當一系列的子問題都解決之後(所有子問題線程都已經await()),此時將柵欄打開,所有子問題線程被釋放,而柵欄位置可以留着下次使用。

接着上面的例子,還是這三個工人,不過這一次,這三個工人自由了,老闆不用檢查他們任務了,他們三個合作建橋,有三個樁,每人打一個,同時打完之後才能一起搭橋(搭橋需要三人一起合作)。也就是說三個人都打完樁之後才能繼續工作。

package lock;

import java.util.concurrent.CyclicBarrier;

/**
 * @author:peng
 * @date: 2018/7/26 21:09
 */
public class CycWork implements Runnable {


    private CyclicBarrier cyclicBarrier;
    private String name;

    public CycWork(CyclicBarrier cyclicBarrier, String name) {
        this.name = name;
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        System.out.println(name + "正在打樁,畢竟不輕鬆。。。。。");

        try {
            System.out.println(name + "不容易,終於把樁打完了。。。。");
            cyclicBarrier.await();
            Thread.sleep(5000);

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }

        System.out.println(name + ":其他逗b把樁都打完了,又得忙活了。。。");


    }

}

測試程序

package lock;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 柵欄測試用例
 *
 * @author:peng
 * @date: 2018/7/26 21:09
 */
public class CyclicBarrierTest {

    public static void main(String[] args) {
        ExecutorService executorpool = Executors.newFixedThreadPool(3);
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

        CycWork work1 = new CycWork(cyclicBarrier, "張三");
        CycWork work2 = new CycWork(cyclicBarrier, "李四");
        CycWork work3 = new CycWork(cyclicBarrier, "王五");

        executorpool.execute(work1);
        executorpool.execute(work2);
        executorpool.execute(work3);

        executorpool.shutdown();

    }

}

運行結果:

李四正在打樁,畢竟不輕鬆。。。。。
張三正在打樁,畢竟不輕鬆。。。。。
王五正在打樁,畢竟不輕鬆。。。。。
李四不容易,終於把樁打完了。。。。
張三不容易,終於把樁打完了。。。。
王五不容易,終於把樁打完了。。。。
王五:其他逗b把樁都打完了,又得忙活了。。。
李四:其他逗b把樁都打完了,又得忙活了。。。
張三:其他逗b把樁都打完了,又得忙活了。。。

Semaphore(信號量)

  • 1、獲得許可 acquire()
  • 2、釋放許可 release()
package lock;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author:peng
 * @date: 2018/7/26 21:21
 */
public class SemaphoreTest {

    private Semaphore smp = new Semaphore(3);
    private Random rnd = new Random();

    class TaskDemo implements Runnable {
        private String id;

        TaskDemo(String id) {
            this.id = id;
        }

        @Override
        public void run() {
            try {
                smp.acquire();
                System.out.println("Thread " + id + " is working");
                Thread.sleep(rnd.nextInt(3000));
                smp.release();
                System.out.println("Thread " + id + " is over");
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) {
        SemaphoreTest semaphoreDemo = new SemaphoreTest();
        //注意我創建的線程池類型,
        ExecutorService se = Executors.newCachedThreadPool();
        se.submit(semaphoreDemo.new TaskDemo("a"));
        se.submit(semaphoreDemo.new TaskDemo("b"));
        se.submit(semaphoreDemo.new TaskDemo("c"));
        se.submit(semaphoreDemo.new TaskDemo("d"));
        se.submit(semaphoreDemo.new TaskDemo("e"));
        se.submit(semaphoreDemo.new TaskDemo("f"));
        se.shutdown();
    }


}

引用鏈接:

https://blog.csdn.net/yujin753/article/details/46125283
http://peaceland.cn/2016/03/28/cyclicbarrier_semaphore/
https://www.cnblogs.com/NewMan13/p/7792365.html

CountDownLatch、CyclicBarrier、Semaphore的區別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章