countdowlatch 和 cyclicbarrier 的內部原理和用法


http://www.wtoutiao.com/p/1b4Lvvv.html

http://www.jb51.net/article/34729.htm

http://blog.csdn.net/lantian0802/article/details/9720993

http://aaron-han.iteye.com/blog/1591755

例子

1.CountDownLatch減計數,CyclicBarrier加計數。
2.CountDownLatch是一次性的,CyclicBarrier可以重用。

 

1、CountDownLatch

一個非常典型的應用場景是:有一個任務想要往下執行,但必須要等到其他的任務執行完畢后才可以繼續往下執行。假如我們這個想要繼續往下執行的任務調用一個CountDownLatch對象的await()方法,其他的任務執行完自己的任務后調用同一個CountDownLatch對象上的countDown()方法,這個調用await()方法的任務將一直阻塞等待,直到這個CountDownLatch對象的計數值減到0為止。

 

 

用法:用給定的計數初始化CountDownLath。調用countDown()方法計數減 1,在計數被減到 0之前,調用await方法會一直阻塞。減為 0之后,則會迅速釋放所有阻塞等待的線程,並且調用await操作會立即返回。

ps:CountDownLath計數無法被重置,如果需要重置計數,請考慮使用CyclicBarrier.

有五個人,一個裁判。這五個人同時跑,裁判開始計時,五個人都到終點了,裁判喊停,然后統計這五個人從開始跑到最后一個撞線用了多長時間。

 1     import java.util.concurrent.CountDownLatch;  
 2       
 3     public class Race {  
 4       
 5         public static void main(String[] args) {  
 6             final int num = 5;  
 7             final CountDownLatch begin = new CountDownLatch(1);  
 8             final CountDownLatch end = new CountDownLatch(num);  
 9       
10             for (int i = 0; i < num; i++) {  
11                 new Thread(new AWorker(i, begin, end)).start();  
12             }  
13       
14             // judge prepare...  
15             try {  
16                 Thread.sleep((long) (Math.random() * 5000));  
17             } catch (InterruptedException e1) {  
18                 e1.printStackTrace();  
19             }  
20       
21             System.out.println("judge say : run !");  
22             begin.countDown();  
23             long startTime = System.currentTimeMillis();  
24       
25             try {  
26                 end.await();  
27             } catch (InterruptedException e) {  
28                 e.printStackTrace();  
29             } finally {  
30                 long endTime = System.currentTimeMillis();  
31                 System.out.println("judge say : all arrived !");  
32                 System.out.println("spend time: " + (endTime - startTime));  
33             }  
34       
35         }  
36       
37     }  
38       
39     class AWorker implements Runnable {  
40         final CountDownLatch begin;  
41         final CountDownLatch end;  
42         final int id;  
43       
44         public AWorker(final int id, final CountDownLatch begin,  
45                 final CountDownLatch end) {  
46             this.id = id;  
47             this.begin = begin;  
48             this.end = end;  
49         }  
50       
51         @Override  
52         public void run() {  
53             try {  
54                 System.out.println(this.id + " ready !");  
55                 begin.await();  
56                 // run...  
57                 Thread.sleep((long) (Math.random() * 10000));  
58             } catch (Throwable e) {  
59                 e.printStackTrace();  
60             } finally {  
61                 System.out.println(this.id + " arrived !");  
62                 end.countDown();  
63             }  
64         }  
65       
66     }  

輸出:

4 ready !
1 ready !
3 ready !
2 ready !
judge say : run !
1 arrived !
4 arrived !
0 arrived !
2 arrived !
3 arrived !
judge say : all arrived !
spend time: 9636
View Code

CountDownLatch強調的是一個線程(或多個)需要等待另外的n個線程干完某件事情之后才能繼續執行。 上述例子,main線程是裁判,5個AWorker是跑步的。運動員先准備,裁判喊跑,運動員才開始跑(這是第一次同步,對應begin)。5個人誰跑到終點了,countdown一下,直到5個人全部到達,裁判喊停(這是第二次同步,對應end),然后算時間。

 

2、使用cyclicbarrier

定義:是一個同步輔助類,它允許一組線程互相等待,直到到達某個公共的屏障點,所有線程一起繼續執行或者返回。一個特性就是CyclicBarrier支持一個可選的Runnable命令,在一組線程中的最后一個線程到達之后,該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新此共享狀態,此屏障操作很有用。

用法:用計數 N 初始化CyclicBarrier, 每調用一次await,線程阻塞,並且計數+1(計數起始是0),當計數增長到指定計數N時,所有阻塞線程會被喚醒。繼續調用await也將迅速返回。

規定五個人只要都跑到終點了,大家可以喝啤酒。但是,只要有一個人沒到終點,就不能喝。 這里也沒有要求大家要同時起跑

 1     import java.util.concurrent.BrokenBarrierException;  
 2     import java.util.concurrent.CyclicBarrier;  
 3       
 4     public class Beer {  
 5       
 6         public static void main(String[] args) {  
 7             final int count = 5;  
 8             final CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() {  
 9                 @Override  
10                 public void run() {  
11                     System.out.println("drink beer!");  
12                 }  
13             });  
14       
15             // they do not have to start at the same time...  
16             for (int i = 0; i < count; i++) {  
17                 new Thread(new Worker(i, barrier)).start();  
18             }  
19         }  
20       
21     }  
22       
23     class Worker implements Runnable {  
24         final int id;  
25         final CyclicBarrier barrier;  
26       
27         public Worker(final int id, final CyclicBarrier barrier) {  
28             this.id = id;  
29             this.barrier = barrier;  
30         }  
31       
32         @Override  
33         public void run() {  
34             try {  
35                 System.out.println(this.id + "starts to run !");  
36                 Thread.sleep((long) (Math.random() * 10000));  
37                 System.out.println(this.id + "arrived !");  
38                 this.barrier.await();  
39             } catch (InterruptedException e) {  
40                 e.printStackTrace();  
41             } catch (BrokenBarrierException e) {  
42                 e.printStackTrace();  
43             }  
44         }  
45     }  

輸出:

0starts to run !
2starts to run !
1starts to run !
3starts to run !
4starts to run !
1arrived !
3arrived !
2arrived !
0arrived !
4arrived !
drink beer!
View Code

CyclicBarrier強調的是n個線程,大家相互等待,只要有一個沒完成,所有人都得等着。正如上例,只有5個人全部跑到終點,大家才能開喝,否則只能全等着。

 

這樣應該就清楚一點了,對於CountDownLatch來說,重點是那個“一個線程”, 是它在等待, 而另外那N的線程在把“某個事情”做完之后可以繼續等待,可以終止。而對於CyclicBarrier來說,重點是那N個線程,他們之間任何一個沒有完成,所有的線程都必須等待。

 


免責聲明!

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



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