介紹
一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程後可以重用,所以稱它為循環 的 barrier。
CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最後一個線程到達之後(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作 很有用。
主要方法
//設置parties、count及barrierCommand屬性。
CyclicBarrier(int):
//當await的數量到達了設定的數量後,首先執行該Runnable對象。
CyclicBarrier(int,Runnable):
//通知barrier已完成線程
await():
應用場景
1:CyclicBarrier 表示大家彼此等待,大家集合好後才開始出發,分散活動後又在i指定地點集合碰面,這就好比整個公司的人員利用周末時間集體郊游一樣,先各自從家出發到公司集合後,再同時出發到公園游玩,在指定地點集合後再同時開始就餐。
代碼:
public class CyclicBarrierTest {
public static void main(String[] args){
ExecutorService pool = Executors.newCachedThreadPool();
final CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
for (int i = 0; i < 3; i++) {
Runnable runnable = new Runnable() {
@Override
public void run(){
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"到達地點一,當前等待人數為"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"繼續出發":"繼續等待"));
try {
cyclicBarrier.await();//障礙等待點
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"到達地點二,當前等待人數為"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"繼續出發":"繼續等待"));
try {
cyclicBarrier.await();//障礙等待點
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"到達地點三,當前等待人數為"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"人齊了出發":"繼續等待"));
try {
cyclicBarrier.await();//障礙等待點
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
pool.execute(runnable);
}
pool.shutdown();
}
}
執行結果:
pool-1-thread-3到達地點一,當前等待人數為1繼續等待
pool-1-thread-1到達地點一,當前等待人數為2繼續等待
pool-1-thread-2到達地點一,當前等待人數為3繼續出發
pool-1-thread-1到達地點二,當前等待人數為1繼續等待
pool-1-thread-3到達地點二,當前等待人數為2繼續等待
pool-1-thread-2到達地點二,當前等待人數為3繼續出發
pool-1-thread-3到達地點三,當前等待人數為1繼續等待
pool-1-thread-2到達地點三,當前等待人數為2繼續等待
pool-1-thread-1到達地點三,當前等待人數為3人齊了出發
2:在某種需求中,比如一個大型的任務,常常需要分配好多子任務去執行,只有當所有子任務都執行完成時候,才能執行主任務,這時候,就可以選擇CyclicBarrier了。
代碼:
public class CyclicBarrierTest1 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
CyclicBarrier barrier = new CyclicBarrier(5, new mainTask());
for (int i = 0; i < 5; i++) {
subTask subTask = new subTask(barrier);
threadPool.execute(subTask);
}
threadPool.shutdown();
}
}
class subTask implements Runnable{
private CyclicBarrier barrier;
public subTask(CyclicBarrier barrier) {
super();
this.barrier = barrier;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在執行");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"執行完畢,等待其他結果");
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class mainTask implements Runnable{
@Override
public void run() {
System.out.println("總任務執行完畢");
}
}
執行結果:
pool-1-thread-2正在執行
pool-1-thread-3正在執行
pool-1-thread-1正在執行
pool-1-thread-4正在執行
pool-1-thread-5正在執行
pool-1-thread-2執行完畢,等待其他結果
pool-1-thread-5執行完畢,等待其他結果
pool-1-thread-1執行完畢,等待其他結果
pool-1-thread-4執行完畢,等待其他結果
pool-1-thread-3執行完畢,等待其他結果
總任務執行完畢
另外,CyclicBarrier是可以重用的,它可以在使用完後繼續使用,這就是Cyclic(循環)的意思。