java多线程-CyclicBarrier
- 介绍
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 支持一个可选的 Runnable
命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
- 主要方法
-
1 //设置parties、count及barrierCommand属性。 2 CyclicBarrier(int): 3 //当await的数量到达了设定的数量后,首先执行该Runnable对象。 4 CyclicBarrier(int,Runnable): 5 //通知barrier已完成线程 6 await():
-
应用场景
1:CyclicBarrier 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在i指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐。
代码:
1 public class CyclicBarrierTest { 2 public static void main(String[] args){ 3 ExecutorService pool = Executors.newCachedThreadPool(); 4 final CyclicBarrier cyclicBarrier = new CyclicBarrier(3); 5 6 for (int i = 0; i < 3; i++) { 7 Runnable runnable = new Runnable() { 8 @Override 9 public void run(){ 10 try { 11 Thread.sleep(new Random().nextInt(5000)); 12 } catch (InterruptedException e) { 13 // TODO Auto-generated catch block 14 e.printStackTrace(); 15 } 16 System.out.println(Thread.currentThread().getName()+"到达地点一,当前等待人数为"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"继续出发":"继续等待")); 17 try { 18 cyclicBarrier.await();//障碍等待点 19 } catch (InterruptedException e) { 20 // TODO Auto-generated catch block 21 e.printStackTrace(); 22 } catch (BrokenBarrierException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 try { 27 Thread.sleep(new Random().nextInt(5000)); 28 } catch (InterruptedException e) { 29 // TODO Auto-generated catch block 30 e.printStackTrace(); 31 } 32 System.out.println(Thread.currentThread().getName()+"到达地点二,当前等待人数为"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"继续出发":"继续等待")); 33 try { 34 cyclicBarrier.await();//障碍等待点 35 } catch (InterruptedException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } catch (BrokenBarrierException e) { 39 // TODO Auto-generated catch block 40 e.printStackTrace(); 41 } 42 try { 43 Thread.sleep(new Random().nextInt(5000)); 44 } catch (InterruptedException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 System.out.println(Thread.currentThread().getName()+"到达地点三,当前等待人数为"+(cyclicBarrier.getNumberWaiting()+1)+(cyclicBarrier.getNumberWaiting()+1==3?"人齐了出发":"继续等待")); 49 try { 50 cyclicBarrier.await();//障碍等待点 51 } catch (InterruptedException e) { 52 // TODO Auto-generated catch block 53 e.printStackTrace(); 54 } catch (BrokenBarrierException e) { 55 // TODO Auto-generated catch block 56 e.printStackTrace(); 57 } 58 } 59 }; 60 pool.execute(runnable); 61 } 62 pool.shutdown(); 63 } 64 }
执行结果:
1 pool-1-thread-3到达地点一,当前等待人数为1继续等待 2 pool-1-thread-1到达地点一,当前等待人数为2继续等待 3 pool-1-thread-2到达地点一,当前等待人数为3继续出发 4 pool-1-thread-1到达地点二,当前等待人数为1继续等待 5 pool-1-thread-3到达地点二,当前等待人数为2继续等待 6 pool-1-thread-2到达地点二,当前等待人数为3继续出发 7 pool-1-thread-3到达地点三,当前等待人数为1继续等待 8 pool-1-thread-2到达地点三,当前等待人数为2继续等待 9 pool-1-thread-1到达地点三,当前等待人数为3人齐了出发
2:在某种需求中,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择CyclicBarrier了。
代码:
1 public class CyclicBarrierTest1 { 2 public static void main(String[] args) { 3 ExecutorService threadPool = Executors.newCachedThreadPool(); 4 CyclicBarrier barrier = new CyclicBarrier(5, new mainTask()); 5 for (int i = 0; i < 5; i++) { 6 subTask subTask = new subTask(barrier); 7 threadPool.execute(subTask); 8 } 9 threadPool.shutdown(); 10 } 11 } 12 13 class subTask implements Runnable{ 14 private CyclicBarrier barrier; 15 16 public subTask(CyclicBarrier barrier) { 17 super(); 18 this.barrier = barrier; 19 } 20 @Override 21 public void run() { 22 System.out.println(Thread.currentThread().getName()+"正在执行"); 23 try { 24 Thread.sleep(5000); 25 } catch (InterruptedException e) { 26 // TODO Auto-generated catch block 27 e.printStackTrace(); 28 } 29 System.out.println(Thread.currentThread().getName()+"执行完毕,等待其他结果"); 30 try { 31 barrier.await(); 32 } catch (InterruptedException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } catch (BrokenBarrierException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 40 } 41 } 42 class mainTask implements Runnable{ 43 44 @Override 45 public void run() { 46 System.out.println("总任务执行完毕"); 47 } 48 49 }
执行结果:
1 pool-1-thread-2正在执行 2 pool-1-thread-3正在执行 3 pool-1-thread-1正在执行 4 pool-1-thread-4正在执行 5 pool-1-thread-5正在执行 6 pool-1-thread-2执行完毕,等待其他结果 7 pool-1-thread-5执行完毕,等待其他结果 8 pool-1-thread-1执行完毕,等待其他结果 9 pool-1-thread-4执行完毕,等待其他结果 10 pool-1-thread-3执行完毕,等待其他结果 11 总任务执行完毕
另外,CyclicBarrier是可以重用的,它可以在使用完后继续使用,这就是Cyclic(循环)的意思。