玩碎Java之CountDownLatch / Semaphore / CyclicBarrier

CountDownLatch(倒計數器) - 人去樓空:人都走沒了,才能鎖門

作用:一個線程(或者多個), 等待另外N個線程完成某個事情之後才能執行。

實例:學生放學了,老師等所有學生都離開後,最後離開並鎖門(走一個減1,直到走完爲0)

(圖片來自互聯網,如有侵權,請聯繫刪除)

代碼

public class CountDownLatchDemo1 {

    private static int COUNT = 8; // 該教室有8個學生

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(COUNT);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new GotoMeat(String.valueOf(i), latch));
        }
        latch.await();
        executorService.shutdown();

        System.out.println("學生都走了,老師可以鎖門了!");
    }

    public static class GotoMeat implements Runnable{
        private String name;
        private CountDownLatch latch;

        public GotoMeat(String name, CountDownLatch latch) {
            this.name = name;
            this.latch = latch;
        }


        @Override
        public void run() {
            System.out.println("學生 " + name + " 已經離開... ");
            latch.countDown();
        }
    }
}

Semaphore(信號量,限流) - 食堂打飯:只有3個窗口可以同時打飯

作用:Semaphore用於限制可以訪問某些資源(物理或邏輯的)的線程數目,他維護了一個許可證集合,有多少資源需要限制就維護多少許可證集合,假如這裏有N個資源,那就對應於N個許可證,同一時刻也只能有N個線程訪問。一個線程獲取許可證就調用acquire方法,用完了釋放資源就調用release方法。

實例:高速路收費站有5個收費口,不管後面有多少輛車,每次只能通行5輛

(圖片來自網絡)

代碼

public class SemaphoreDemo1 {

    private static int COUNT = 5; // 共有5輛車等待通過收費口
    private static int LIMIT = 2; // 有2個收費口

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(LIMIT);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new PassThroughTheToll(String.valueOf(i), semaphore));
        }
        executorService.shutdown();
    }

    public static class PassThroughTheToll implements Runnable {

        private String name;
        private Semaphore semaphore;

        public PassThroughTheToll(String name, Semaphore semaphore) {
            this.name = name;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("車輛 " + name + "拿到了通過收費站的許可...");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("車輛 " + name + "通過收費站,釋放了許可~~~");
                semaphore.release();
            }
        }
    }
}

CyclicBarrier(屏障) - 運動員互相等待就位:全就位後,裁判發槍

作用:CyclicBarrier允許一組線程在到達某個柵欄點(common barrier point)互相等待,直到最後一個線程到達柵欄點,柵欄纔會打開,處於阻塞狀態的線程恢復繼續執行。

實例:師徒四人,都準備好了(到達公共屏障點common barrier point,相當於一個障礙點),再一起走(在障礙點一個都不能少,到齊後才能一起幹大事)

實例2:田徑比賽,各位運動員都準備好就位之後,裁判發槍

查看源圖像

(圖片來源互聯網)

代碼

public class CyclicBarrierDemo1 {

    private static int COUNT = 4; // 師徒四人

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(COUNT);
        String[] names = {"唐老闆", "猴哥", "八戒", "沙和尚"};

        ExecutorService executorService = Executors.newFixedThreadPool(COUNT);
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new Travel(names[i], cyclicBarrier));
        }
        executorService.shutdown();
    }

    static class Travel implements Runnable {

        private String name;
        private CyclicBarrier cyclicBarrier;

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

        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(1+(new Random().nextInt(3)));
                System.out.println(name + "已就位...,等待其他成員到來");
                cyclicBarrier.await();
                System.out.println(name + " :看到所有成員已到齊,四人一起過流沙河");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

CountDownLatch 與 CyclicBarrier 的區別

CountDownLatch CyclicBarrier
減計數方式 加計數方式
計數爲0時,釋放所等有待的線程 計數達到指定值時,釋放所有等待的線程
計數爲0時,無法重置 計數達到指定值時,計數置爲0,重新開始

調用countDown()方法減1

調用await()方法只進行阻塞,對計數沒任何影響

await()方法計數加1,

若加1後的值不等於初始指定的值,則線程阻塞

不可重複利用 可重複利用

CountDownLatch是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減;

CyclicBarrier更像是一個閥門,需要所有線程都要到達,閥門才能打開,然後繼續執行。

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