CyclicBarrier是一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程后可以重用,所以稱它為循環 的 barrier。
CyclicBarrier類似於CountDownLatch也是個計數器, 不同的是CyclicBarrier數的是調用了CyclicBarrier.await()進入等待的線程數, 當線程數達到了CyclicBarrier初始時規定的數目時,所有進入等待狀態的線程被喚醒並繼續。 CyclicBarrier就象它名字的意思一樣,可看成是個障礙, 所有的線程必須到齊后才能一起通過這個障礙。 CyclicBarrier初始時還可帶一個Runnable的參數,此Runnable任務在CyclicBarrier的數目達到后,所有其它線程被喚醒前被執行。
構造方法摘要 | |
---|---|
CyclicBarrier(int parties) 創建一個新的 CyclicBarrier,它將在給定數量的參與者(線程)處於等待狀態時啟動,但它不會在每個 barrier 上執行預定義的操作。 |
|
CyclicBarrier(int parties, Runnable barrierAction) 創建一個新的 CyclicBarrier,它將在給定數量的參與者(線程)處於等待狀態時啟動,並在啟動 barrier 時執行給定的屏障操作,該操作由最后一個進入 barrier 的線程執行 |
方法摘要 | |
---|---|
int |
await() 在所有 參與者 都已經在此 barrier 上調用 await 方法之前,將一直等待。 |
int |
await(long timeout, TimeUnit unit) 在所有 參與者 都已經在此屏障上調用 await 方法之前,將一直等待。 |
int |
getNumberWaiting() 返回當前在屏障處等待的參與者數目。 |
int |
getParties() 返回要求啟動此 barrier 的參與者數目。 |
boolean |
isBroken() 查詢此屏障是否處於損壞狀態。 |
void |
reset() 將屏障重置為其初始狀態。 |
1 package com.thread; 2 import java.util.concurrent.CyclicBarrier; 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.Semaphore; 6 7 public class CyclicBarrierTest { 8 9 public static void main(String[] args) { 10 ExecutorService service = Executors.newCachedThreadPool(); 11 final CyclicBarrier cb = new CyclicBarrier(3);//創建CyclicBarrier對象並設置3個公共屏障點 12 for(int i=0;i<3;i++){ 13 Runnable runnable = new Runnable(){ 14 public void run(){ 15 try { 16 Thread.sleep((long)(Math.random()*10000)); 17 System.out.println("線程" + Thread.currentThread().getName() + 18 "即將到達集合地點1,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 19 cb.await();//到此如果沒有達到公共屏障點,則該線程處於等待狀態,如果達到公共屏障點則所有處於等待的線程都繼續往下運行 20 21 Thread.sleep((long)(Math.random()*10000)); 22 System.out.println("線程" + Thread.currentThread().getName() + 23 "即將到達集合地點2,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 24 cb.await(); 25 Thread.sleep((long)(Math.random()*10000)); 26 System.out.println("線程" + Thread.currentThread().getName() + 27 "即將到達集合地點3,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 28 cb.await(); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 } 33 }; 34 service.execute(runnable); 35 } 36 service.shutdown(); 37 } 38 }
線程pool-1-thread-1即將到達集合地點1,當前已有0個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點1,當前已有1個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點1,當前已有2個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點2,當前已有0個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點2,當前已有1個已經到達,正在等候 線程pool-1-thread-1即將到達集合地點2,當前已有2個已經到達,正在等候 線程pool-1-thread-1即將到達集合地點3,當前已有0個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點3,當前已有1個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點3,當前已有2個已經到達,正在等候
如果在構造CyclicBarrier對象的時候傳了一個Runnable對象進去,則每次到達公共屏障點的時候都最先執行這個傳進去的Runnable,然后再執行處於等待的Runnable。如果把上面的例子改成下面這樣:
1 package com.thread; 2 import java.util.concurrent.CyclicBarrier; 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.Semaphore; 6 7 public class CyclicBarrierTest { 8 9 public static void main(String[] args) { 10 ExecutorService service = Executors.newCachedThreadPool(); 11 //final CyclicBarrier cb = new CyclicBarrier(3);//創建CyclicBarrier對象並設置3個公共屏障點 12 final CyclicBarrier cb = new CyclicBarrier(3,new Runnable(){ 13 @Override 14 public void run() { 15 System.out.println("********我最先執行***********"); 16 } 17 }); 18 for(int i=0;i<3;i++){ 19 Runnable runnable = new Runnable(){ 20 public void run(){ 21 try { 22 Thread.sleep((long)(Math.random()*10000)); 23 System.out.println("線程" + Thread.currentThread().getName() + 24 "即將到達集合地點1,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 25 cb.await();//到此如果沒有達到公共屏障點,則該線程處於等待狀態,如果達到公共屏障點則所有處於等待的線程都繼續往下運行 26 27 Thread.sleep((long)(Math.random()*10000)); 28 System.out.println("線程" + Thread.currentThread().getName() + 29 "即將到達集合地點2,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 30 cb.await(); //這里CyclicBarrier對象又可以重用 31 Thread.sleep((long)(Math.random()*10000)); 32 System.out.println("線程" + Thread.currentThread().getName() + 33 "即將到達集合地點3,當前已有" + cb.getNumberWaiting() + "個已經到達,正在等候"); 34 cb.await(); 35 } catch (Exception e) { 36 e.printStackTrace(); 37 } 38 } 39 }; 40 service.execute(runnable); 41 } 42 service.shutdown(); 43 } 44 }
則結果如下:
線程pool-1-thread-1即將到達集合地點1,當前已有0個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點1,當前已有1個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點1,當前已有2個已經到達,正在等候 ********我最先執行*********** 線程pool-1-thread-1即將到達集合地點2,當前已有0個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點2,當前已有1個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點2,當前已有2個已經到達,正在等候 ********我最先執行*********** 線程pool-1-thread-1即將到達集合地點3,當前已有0個已經到達,正在等候 線程pool-1-thread-3即將到達集合地點3,當前已有1個已經到達,正在等候 線程pool-1-thread-2即將到達集合地點3,當前已有2個已經到達,正在等候 ********我最先執行***********