CyclicBarrier 公共屏障点

在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等待其他线程都完成某一阶段后再执行,等所有线程都到达某一个阶段后再统一执行。

JDK:

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

 

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

 

 

对于失败的同步尝试,CyclicBarrier 使用了一种快速失败的、要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么其他所有线程(甚至是那些尚未从以前的 await() 中恢复的线程)也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。

JDK地址:

http://www.cjsdn.net/doc/jdk50/java/util/concurrent/CyclicBarrier.html#CyclicBarrier(int, java.lang.Runnable)

 

 

Java代码   收藏代码
  1. //构造方法摘要  
  2. CyclicBarrier(int parties)   
  3.           //创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作。  
  4. CyclicBarrier(int parties, Runnable barrierAction)   
  5.           //创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。  

 

Example1:

Java代码   收藏代码
  1. package tags;  
  2.   
  3. import java.util.Random;  
  4. import java.util.concurrent.CyclicBarrier;  
  5.   
  6. /**  
  7.  * CyclicBarrier调用CyclicBarrier.await()进入等待的线程数, 
  8.  * 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 
  9.  * CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 
  10.  * CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。 
  11.  */  
  12. public class CyclicBarrierTest {  
  13.   
  14.     public static class ComponentThread implements Runnable {  
  15.         CyclicBarrier barrier;// 计数器  
  16.         int ID;    // 组件标识  
  17.         int[] array;    // 数据数组  
  18.   
  19.         // 构造方法  
  20.         public ComponentThread(CyclicBarrier barrier, int[] array, int ID) {  
  21.             this.barrier = barrier;  
  22.             this.ID = ID;  
  23.             this.array = array;  
  24.         }  
  25.   
  26.         public void run() {  
  27.             try {  
  28.                 array[ID] = new Random().nextInt(100);  
  29.                 System.out.println("Component " + ID + " generates: " + array[ID]);  
  30.                 System.out.println("Component " + ID + " sleep"); // 在这里等待Barrier处  
  31.                 barrier.await();  
  32.                 System.out.println("Component " + ID + " awaked");  
  33.                 // 计算数据数组中的当前值和后续值  
  34.                 int result = array[ID] + array[ID + 1];  
  35.                 System.out.println("Component " + ID + " result: " + result);  
  36.             } catch (Exception ex) {  
  37.             }  
  38.         }  
  39.     }  
  40.     /** 
  41.      * 测试CyclicBarrier的用法 
  42.      */  
  43.     public static void testCyclicBarrier() {  
  44.         final int[] array = new int[3];  
  45.         CyclicBarrier barrier = new CyclicBarrier(2new Runnable() {  
  46.             // 在所有线程都到达Barrier时执行  
  47.             public void run() {  
  48.                 System.out.println("testCyclicBarrier run");  
  49.                 array[2] = array[0] + array[1];  
  50.             }  
  51.         });  
  52.   
  53.         // 启动线程  
  54.         new Thread(new ComponentThread(barrier, array, 0)).start();  
  55.         new Thread(new ComponentThread(barrier, array, 1)).start();          
  56.     }  
  57.   
  58.     public static void main(String[] args) {  
  59.         CyclicBarrierTest.testCyclicBarrier();  
  60.     }  
  61. }  

结果:

Component 1 generates: 40

Component 0 generates: 8

Component 1 sleep

Component 0 sleep

testCyclicBarrier run

Component 0 awaked

Component 0 result: 48

Component 1 awaked

Component 1 result: 88

 

 

两个线程分别执行,互不影响 ,执行到barrier.await();时该线程进入等待状态,

当两个线程都执行到barrier.await();时,达到CyclicBarrier启动所需的阻塞线程数,进入到new CyclicBarrier(2, new Runnable()...)里面的方法, 执行完里面的方法后,等待的两个线程再次被唤醒,继续各自执行线程后面的语句。 

 

 

Example2:

 

比如有几个旅行团需要途经深圳、广州、韶关、长沙最后到达武汉。旅行团中有自驾游的,有徒步的,有乘坐旅游大巴的;这些旅行团同时出发,并且每到一个目的地,都要等待其他旅行团到达此地后再同时出发,直到都到达终点站武汉。
这时候CyclicBarrier就可以派上用场。CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。

 

Java代码   收藏代码
  1. package tags;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.concurrent.BrokenBarrierException;  
  6. import java.util.concurrent.CyclicBarrier;  
  7. import java.util.concurrent.ExecutorService;  
  8. import java.util.concurrent.Executors;  
  9.   
  10. public class TestCyclicBarrier {  
  11.     // 徒步需要的时间: Shenzhen, Guangzhou, Shaoguan  
  12.     private static int[] timeWalk = { 5815};  
  13.     // 自驾游  
  14.     private static int[] timeSelf = { 134};  
  15.     // 旅游大巴  
  16.     private static int[] timeBus = { 246};  
  17.   
  18.     static String now() {  
  19.         SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");  
  20.         return sdf.format(new Date()) + ": ";  
  21.     }  
  22.   
  23.     static class Tour implements Runnable {  
  24.         private int[] times;  
  25.         private CyclicBarrier barrier;  
  26.         private String tourName;  
  27.   
  28.         public Tour(CyclicBarrier barrier, String tourName, int[] times) {  
  29.             this.times = times;  
  30.             this.tourName = tourName;  
  31.             this.barrier = barrier;  
  32.         }  
  33.   
  34.         public void run() {  
  35.             try {  
  36.                 Thread.sleep(times[0] * 1000);  //使用 times岔开各组时间,使其显示不同的now()  
  37.                 System.out.println(now() + tourName + " Reached Shenzhen");  
  38.                 barrier.await();  
  39.                   
  40.                 Thread.sleep(times[1] * 1000);  
  41.                 System.out.println(now() + tourName + " Reached Guangzhou");  
  42.                 barrier.await();  
  43.                   
  44.                 Thread.sleep(times[2] * 1000);  
  45.                 System.out.println(now() + tourName + " Reached Shaoguan");               
  46.             } catch (InterruptedException e) {  
  47.             } catch (BrokenBarrierException e) {  
  48.             }  
  49.         }  
  50.     }  
  51.   
  52.     public static void main(String[] args) {  
  53.         // 三个旅行团  
  54.         CyclicBarrier barrier = new CyclicBarrier(3);  
  55.         ExecutorService exec = Executors.newFixedThreadPool(3);  
  56.         exec.submit(new Tour(barrier, "WalkTour", timeWalk));  
  57.         exec.submit(new Tour(barrier, "SelfTour", timeSelf));  
  58.         exec.submit(new Tour(barrier, "BusTour", timeBus));  
  59.         exec.shutdown();  
  60.     }  
  61. }  

  结果:

 

15:13:11: SelfTour Reached Shenzhen

15:13:12: BusTour Reached Shenzhen

15:13:15: WalkTour Reached Shenzhen

15:13:18: SelfTour Reached Guangzhou

15:13:19: BusTour Reached Guangzhou

15:13:23: WalkTour Reached Guangzhou

15:13:27: SelfTour Reached Shaoguan

15:13:29: BusTour Reached Shaoguan

15:13:38: WalkTour Reached Shaoguan

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值