分享

Java 并发专题 : CyclicBarrier 打造一个安全的门禁系统

 WindySky 2017-10-15

继续并发专题~

这次介绍CyclicBarrier:看一眼API的注释:

  1. /**  
  2.  * A synchronization aid that allows a set of threads to all wait for  
  3.  * each other to reach a common barrier point.  CyclicBarriers are  
  4.  * useful in programs involving a fixed sized party of threads that  
  5.  * must occasionally wait for each other. The barrier is called  
  6.  * <em>cyclic</em> because it can be re-used after the waiting threads  
  7.  * are released.  

大概意思:一个让一组线程同时阻塞到一个位置的同步辅助类。在包含固定线程且线程间必须相互等待的场景中非常有用。cyclic的意思是CyclicBarrier当等待的线程全部释放之后,可以重复使用。(英语水平就这样了。。。。)

CyclicBarrier 类似一个闸门,指定数目的线程都必须到达这个闸门,闸门才会打开。

下面使用CyclicBarrier模拟一个门禁系统:

需求是这样的:到放学时间,所有的学生必须刷卡,然后人数齐了自动开门,统一回家。这个需求刚刚的,避免了把部分孩子丢在学校发生危险,特别是幼儿园或者小学生~~

  1. package com.zhy.concurrency.cyclic;  
  2.   
  3. import java.util.concurrent.BrokenBarrierException;  
  4. import java.util.concurrent.CyclicBarrier;  
  5.   
  6. /** 
  7.  * 安全的门禁系统 
  8.  *  
  9.  * @author zhy 
  10.  *  
  11.  */  
  12. public class CyclicBarrierTest  
  13. {  
  14.   
  15.     /** 
  16.      * 学生总数 
  17.      */  
  18.     private final int STUDENT_COUNT = 10;  
  19.   
  20.     /** 
  21.      * 当人到齐,自动开门程序 
  22.      */  
  23.     final CyclicBarrier barrier = new CyclicBarrier(STUDENT_COUNT,  
  24.             new Runnable()  
  25.             {  
  26.                 @Override  
  27.                 public void run()  
  28.                 {  
  29.                     System.out.println("人到齐了,开门....");  
  30.                 }  
  31.             });  
  32.   
  33.     public void goHome() throws InterruptedException, BrokenBarrierException  
  34.     {  
  35.         System.out.println(Thread.currentThread().getName() + "已刷卡,等待开门回家~");  
  36.         barrier.await();  
  37.         System.out.println(Thread.currentThread().getName() + "放学回家~");  
  38.     }  
  39.   
  40.     public static void main(String[] args) throws InterruptedException,  
  41.             BrokenBarrierException  
  42.     {  
  43.   
  44.         final CyclicBarrierTest instance = new CyclicBarrierTest();  
  45.   
  46.         /** 
  47.          * 每个线程代表一个学生 
  48.          */  
  49.         for (int i = 0; i < instance.STUDENT_COUNT; i++)  
  50.         {  
  51.             new Thread("学生" + i +"  " )  
  52.             {  
  53.                 public void run()  
  54.                 {  
  55.   
  56.                     try  
  57.                     {  
  58.                         instance.goHome();  
  59.                     } catch (InterruptedException e)  
  60.                     {  
  61.                         e.printStackTrace();  
  62.                     } catch (BrokenBarrierException e)  
  63.                     {  
  64.                         e.printStackTrace();  
  65.                     }  
  66.   
  67.                 };  
  68.   
  69.             }.start();  
  70.         }  
  71.   
  72.     }  
  73. }  

输出结果:

  1. 学生1  已刷卡,等待开门回家~  
  2. 学生3  已刷卡,等待开门回家~  
  3. 学生5  已刷卡,等待开门回家~  
  4. 学生9  已刷卡,等待开门回家~  
  5. 学生7  已刷卡,等待开门回家~  
  6. 学生0  已刷卡,等待开门回家~  
  7. 学生2  已刷卡,等待开门回家~  
  8. 学生6  已刷卡,等待开门回家~  
  9. 学生8  已刷卡,等待开门回家~  
  10. 学生4  已刷卡,等待开门回家~  
  11. 人到齐了,开门....  
  12. 学生4  放学回家~  
  13. 学生1  放学回家~  
  14. 学生3  放学回家~  
  15. 学生5  放学回家~  
  16. 学生9  放学回家~  
  17. 学生2  放学回家~  
  18. 学生6  放学回家~  
  19. 学生0  放学回家~  
  20. 学生7  放学回家~  
  21. 学生8  放学回家~  

哈哈,如果哪个幼儿园用了这么一套系统,孩子应该不会丢学校了吧,,,,开玩笑了;;

CyclicBarrier把所有的线程都阻塞在一个阀门位置,然后等到等待的线程数到达预设的值,就打开这个阀门。记得是阻塞线程,不是阻塞操作,在同一个线程使劲掉await是没什么效果的。


上面的例子显示了CyclicBarrier的基本用法,但是cyclic的功能并没有显示出来,既然注释中讲了,我们有必要来个例子看看:

我们改造下我们的门禁,毕竟刷卡好不现实,现在需求是这样的:学生一个人走太危险,现在门卫放学在门口守着,让学生3个一组的走。

  1. package com.zhy.concurrency.cyclic;  
  2.   
  3. import java.util.concurrent.BrokenBarrierException;  
  4. import java.util.concurrent.CyclicBarrier;  
  5.   
  6. /** 
  7.  * 改造后的门禁系统 
  8.  *  
  9.  * @author zhy 
  10.  *  
  11.  */  
  12. public class CyclicBarrierTest2  
  13. {  
  14.   
  15.     /** 
  16.      * 学生总数 
  17.      */  
  18.     private final int STUDENT_COUNT = 12;  
  19.   
  20.     /** 
  21.      * 每3个人一组出门 
  22.      */  
  23.     final CyclicBarrier barrier = new CyclicBarrier(3,  
  24.             new Runnable()  
  25.             {  
  26.                 @Override  
  27.                 public void run()  
  28.                 {  
  29.                     System.out.println("有3个学生到齐了,放行....");  
  30.                 }  
  31.             });  
  32.   
  33.     public void goHome() throws InterruptedException, BrokenBarrierException  
  34.     {  
  35.         System.out.println(Thread.currentThread().getName() + "已刷卡,等待开门回家~");  
  36.         barrier.await();  
  37.     }  
  38.   
  39.     public static void main(String[] args) throws InterruptedException,  
  40.             BrokenBarrierException  
  41.     {  
  42.   
  43.         final CyclicBarrierTest2 instance = new CyclicBarrierTest2();  
  44.   
  45.         /** 
  46.          * 每个线程代表一个学生 
  47.          */  
  48.         for (int i = 0; i < instance.STUDENT_COUNT; i++)  
  49.         {  
  50.             new Thread("学生" + i +"  " )  
  51.             {  
  52.                 public void run()  
  53.                 {  
  54.   
  55.                     try  
  56.                     {  
  57.                         instance.goHome();  
  58.                     } catch (InterruptedException e)  
  59.                     {  
  60.                         e.printStackTrace();  
  61.                     } catch (BrokenBarrierException e)  
  62.                     {  
  63.                         e.printStackTrace();  
  64.                     }  
  65.   
  66.                 };  
  67.   
  68.             }.start();  
  69.         }  
  70.   
  71.     }  
  72. }  
输出结果:

  1. 学生0  已刷卡,等待开门回家~  
  2. 学生1  已刷卡,等待开门回家~  
  3. 学生2  已刷卡,等待开门回家~  
  4. 有3个学生到齐了,放行....  
  5. 学生3  已刷卡,等待开门回家~  
  6. 学生5  已刷卡,等待开门回家~  
  7. 学生7  已刷卡,等待开门回家~  
  8. 有3个学生到齐了,放行....  
  9. 学生4  已刷卡,等待开门回家~  
  10. 学生9  已刷卡,等待开门回家~  
  11. 学生6  已刷卡,等待开门回家~  
  12. 有3个学生到齐了,放行....  
  13. 学生11  已刷卡,等待开门回家~  
  14. 学生10  已刷卡,等待开门回家~  
  15. 学生8  已刷卡,等待开门回家~  
  16. 有3个学生到齐了,放行....  

这个例子充分的体现了CyclicBarrier的复用性,是吧,这样的系统或许更实在些,0成本~哈哈~。


好了,有兴趣的欢迎留言、





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多