Java的CountDownLatch和CyclicBarrier的理解和區別


CountDownLatch和CyclicBarrier的功能看起來很相似,不易區分,有一種謎之的神秘。本文將通過通俗的例子並結合代碼講解兩者的使用方法和區別。

 

CountDownLatch和CyclicBarrier都是java.util.concurrent包下面的多線程工具類。

 

從字面上理解,CountDown表示減法計數,Latch表示門閂的意思,計數為0的時候就可以打開門閂了。Cyclic Barrier表示循環的障礙物。兩個類都含有這一個意思:對應的線程都完成工作之后再進行下一步動作,也就是大家都准備好之后再進行下一步。然而兩者最大的區別是,進行下一步動作的動作實施者是不一樣的。這里的“動作實施者”有兩種,一種是主線程(即執行main函數),另一種是執行任務的其他線程,后面叫這種線程為“其他線程”,區分於主線程。對於CountDownLatch,當計數為0的時候,下一步的動作實施者是main函數;對於CyclicBarrier,下一步動作實施者是“其他線程”。

 

下面舉例說明:

 

對於CountDownLatch,其他線程為游戲玩家,比如英雄聯盟,主線程為控制游戲開始的線程。在所有的玩家都准備好之前,主線程是處於等待狀態的,也就是游戲不能開始。當所有的玩家准備好之后,下一步的動作實施者為主線程,即開始游戲。

 

我們使用代碼模擬這個過程,我們模擬了三個玩家,在三個玩家都准備好之后,游戲才能開始。代碼的輸出結果為:

 

正在等待所有玩家准備好

player0 已經准備好了, 所使用的時間為 1.235s

player2 已經准備好了, 所使用的時間為 1.279s

player3 已經准備好了, 所使用的時間為 1.358s

player1 已經准備好了, 所使用的時間為 2.583s

開始游戲

1

2

3

4

5

6

CountDownLatch的代碼:

 

import java.util.Random;

import java.util.concurrent.CountDownLatch;

 

public class CountDownLatchTest {

 

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch latch = new CountDownLatch(4);

        for(int i = 0; i < latch.getCount(); i++){

            new Thread(new MyThread(latch), "player"+i).start();

        }

        System.out.println("正在等待所有玩家准備好");

        latch.await();

        System.out.println("開始游戲");

    }

 

    private static class MyThread implements Runnable{

        private CountDownLatch latch ;

 

        public MyThread(CountDownLatch latch){

            this.latch = latch;

        }

 

        @Override

        public void run() {

            try {

                Random rand = new Random();

                int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//產生1000到3000之間的隨機整數

                Thread.sleep(randomNum);

                System.out.println(Thread.currentThread().getName()+" 已經准備好了, 所使用的時間為 "+((double)randomNum/1000)+"s");

                latch.countDown();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

 

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

對於CyclicBarrier,假設有一家公司要全體員工進行團建活動,活動內容為翻越三個障礙物,每一個人翻越障礙物所用的時間是不一樣的。但是公司要求所有人在翻越當前障礙物之后再開始翻越下一個障礙物,也就是所有人翻越第一個障礙物之后,才開始翻越第二個,以此類推。類比地,每一個員工都是一個“其他線程”。當所有人都翻越的所有的障礙物之后,程序才結束。而主線程可能早就結束了,這里我們不用管主線程。

 

我們使用代碼來模擬上面的過程。我們設置了三個員工和三個障礙物。可以看到所有的員工翻越了第一個障礙物之后才開始翻越第二個的,下面是運行結果:

 

main function is finished.

隊友1, 通過了第0個障礙物, 使用了 1.432s

隊友0, 通過了第0個障礙物, 使用了 1.465s

隊友2, 通過了第0個障礙物, 使用了 2.26s

隊友1, 通過了第1個障礙物, 使用了 1.542s

隊友0, 通過了第1個障礙物, 使用了 2.154s

隊友2, 通過了第1個障礙物, 使用了 2.556s

隊友1, 通過了第2個障礙物, 使用了 1.426s

隊友2, 通過了第2個障礙物, 使用了 2.603s

隊友0, 通過了第2個障礙物, 使用了 2.784s

1

2

3

4

5

6

7

8

9

10

代碼:

 

package com.huai.thread;

 

import java.util.Random;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

 

public class CyclicBarrierTest {

    public static void main(String[] args) {

        CyclicBarrier barrier = new CyclicBarrier(3);

        for(int i = 0; i < barrier.getParties(); i++){

            new Thread(new MyRunnable(barrier), "隊友"+i).start();

        }

        System.out.println("main function is finished.");

    }

 

 

    private static class MyRunnable implements Runnable{

        private CyclicBarrier barrier;

 

        public MyRunnable(CyclicBarrier barrier){

            this.barrier = barrier;

        }

 

        @Override

        public void run() {

            for(int i = 0; i < 3; i++) {

                try {

                    Random rand = new Random();

                    int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//產生1000到3000之間的隨機整數

                    Thread.sleep(randomNum);

                    System.out.println(Thread.currentThread().getName() + ", 通過了第"+i+"個障礙物, 使用了 "+((double)randomNum/1000)+"s");

                    this.barrier.await();

                } catch (InterruptedException e) {

                    e.printStackTrace();

                } catch (BrokenBarrierException e) {

                    e.printStackTrace();

                }

            }

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

總結:CountDownLatch和CyclicBarrier都有讓多個線程等待同步然后再開始下一步動作的意思,但是CountDownLatch的下一步的動作實施者是主線程,具有不可重復性;而CyclicBarrier的下一步動作實施者還是“其他線程”本身,具有往復多次實施動作的特點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM