/*该类的说明
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。
CyclicBarrier barrier = new CyclicBarrier(str.length, new RunnableLast());第一个参数值
为这个屏障点
在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。
因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
使用场景
需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier。
CyclicBarrier 类构造函数CyclicBarrier(int parties)有一个整数初始值,这个值表示将在同一个点需要同步的线程数量。
当其中一个线程到达某个阶段点后,它会调用await() 方法来等待其他线程。调用这个方法后,CyclicBarrier阻塞线程进入休眠直到
其他线程到达。当最后一个线程调用CyclicBarrier 类的await() 方法,它唤醒所有等待的线程并继续执行它们的任务。然后如此循环。
CyclicBarrier 类的另一个构造函数CyclicBarrier(int parties, Runnable barrierAction)初始时还可带一个Runnable的参数,
此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。
常用方法说明
CyclicBarrier(int parties) 创建一个新的CyclicBarrier,parties表示有多少个数量的参与者参与。
CyclicBarrier(int parties, Runnable barrierAction) 创建一个新的CyclicBarrier,parties表示有多少个数量的参与者参与。barrierAction会由最后一个进入 barrier 的参与者执行。
int await() 在所有参与者在调用 await方法之前,将一直等待。
int await(long timeout, TimeUnit unit) 在等待时间超过timeout之前,所有参与者在调用 await方法之前,将一直等待。unit表示等待时间的单位。
int getNumberWaiting() 返回当前在屏障处等待的参与者数目。int getParties() 返回要求启动此barrier的参与者数目。
boolean isBroken() 查询此屏障是否处于损坏状态。
void reset() 将屏障重置为其初始状态。
*/
package test.data.com.cyclicbarrier; import com.alibaba.fastjson.*; import org.apache.logging.log4j.*; import java.util.*; import java.util.concurrent.*; /** * @author HUAZAI * @title: * @description: * @return 返回类型 : ** * *
* @throws * @date 18-4-11 下午3:21 */ public class RunnableTest implements Runnable { private static final Logger logger = LogManager.getLogger(RunnableTest.class); private Integer num; private CyclicBarrier cyclicBarrier; private String name; public RunnableTest(Integer num, CyclicBarrier cyclicBarrier, String name) { this.num = num; this.cyclicBarrier = cyclicBarrier; this.name = name; } @Override public void run() { logger.info( this.name + " 已经到了 " + " 他是第 " + (cyclicBarrier.getNumberWaiting() + 1) + " 个到的"); logger.info(JSON.toJSONString(cyclicBarrier)); try { cyclicBarrier.await(); } catch (InterruptedException e) { logger.error(" =========== ", e); } catch (BrokenBarrierException e) { logger.error(" =========== ", e); } try { Thread.sleep(1000 * ((new Random()).nextInt(7))); } catch (InterruptedException e) { logger.error(" =========== ", e); } logger.info(this.name + " 已经到了 所有人已经到齐 一共 " + (cyclicBarrier.getParties()) + " 人"); } }
package test.data.com.cyclicbarrier; import org.apache.logging.log4j.*; /** * @author HUAZAI * @title: * @description: * @return 返回类型 : ** * *
* @throws * @date 18-4-11 下午3:30 */ public class RunnableLast implements Runnable { private static final Logger logger = LogManager.getLogger(RunnableLast.class); @Override public void run() { logger.info("所有人一起去 Happy Go"); } }
package test.data.com.cyclicbarrier; import java.util.concurrent.*; /** * @author HUAZAI * @title: * @description: * @return 返回类型 : ** * *
* @throws * @date 18-4-11 下午3:17 */ public class MyCyclicBarrier { public static void testRun(CyclicBarrier barrier, String... name) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(100); for (int index = 0, size = name.length; index < size; index++) { RunnableTest runnableTest = new RunnableTest(index, barrier, name[index]); executorService.execute(runnableTest); Thread.sleep(1000);//此处如果不进行睡眠操作 会使得cyclicBarrier.getNumberWaiting() 乱掉 并发导致 } executorService.shutdown(); } }
package test.data.com.main; import org.apache.logging.log4j.*; import test.data.com.cyclicbarrier.*; import java.util.*; import java.util.concurrent.*; /** * @author LIUHUA * @title: * @description: * @return 返回类型 : ** * *
* @throws * @date 18-4-2 上午11:42 */ public class MainTest { private static final org.apache.logging.log4j.Logger logger1 = org.apache.logging.log4j.LogManager.getLogger(MainTest.class); public static void main(String[] args) { // testLogger(); String[] str = {"华仔1","华仔2","华仔3","华仔4","华仔5"}; CyclicBarrier barrier = new CyclicBarrier(str.length, new RunnableLast()); try { MyCyclicBarrier.testRun(barrier, str); } catch (InterruptedException e) { e.printStackTrace(); } } }
执行结果
华仔1 已经到了 他是第 1 个到的 如果在MyCyclicBarrier的for中不加sleep 会导致第几个到的数据不准确
{"broken":false,"numberWaiting":0,"parties":5}
华仔2 已经到了 他是第 2 个到的
{"broken":false,"numberWaiting":1,"parties":5}
华仔3 已经到了 他是第 3 个到的
{"broken":false,"numberWaiting":2,"parties":5}
华仔4 已经到了 他是第 4 个到的
{"broken":false,"numberWaiting":3,"parties":5}
华仔5 已经到了 他是第 5 个到的
{"broken":false,"numberWaiting":4,"parties":5}
所有人一起去 Happy Go
华仔4 已经到了 所有人已经到齐 一共 5 人
华仔3 已经到了 所有人已经到齐 一共 5 人
华仔2 已经到了 所有人已经到齐 一共 5 人
华仔5 已经到了 所有人已经到齐 一共 5 人
华仔1 已经到了 所有人已经到齐 一共 5 人
在MyCyclicBarrier的for中不加sleep 会导致第几个到的数据不准确 结果如下
华仔2 已经到了 他是第 1 个到的
华仔3 已经到了 他是第 1 个到的
华仔4 已经到了 他是第 1 个到的
华仔5 已经到了 他是第 1 个到的
华仔1 已经到了 他是第 1 个到的
{"broken":false,"numberWaiting":0,"parties":5}
{"broken":false,"numberWaiting":0,"parties":5}
{"broken":false,"numberWaiting":2,"parties":5}
{"broken":false,"numberWaiting":3,"parties":5}
{"broken":false,"numberWaiting":3,"parties":5}
所有人一起去 Happy Go
华仔2 已经到了 所有人已经到齐 一共 5 人
华仔1 已经到了 所有人已经到齐 一共 5 人
华仔3 已经到了 所有人已经到齐 一共 5 人
华仔5 已经到了 所有人已经到齐 一共 5 人
华仔4 已经到了 所有人已经到齐 一共 5 人