疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

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(循环)的意思。