Bootstrap

CyclicBarrier复杂场景示例

        比如这样一个场景,公司组织10名员工去旅游,先组织大家吃饭,吃完饭在一起坐车去景点。

要求:吃饭:必须10名员工都到座位了才能一起吃饭

           坐车:必须10名员工都上车了,才能发车。

一、代码如下

package com.lsl.utills;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

/**
 * CyclicBarrier复杂场景示例
 * 公司组织10名员工去旅游,包括吃饭和上车去景点游玩
 * 吃饭要求10个员工都到座才能开始一起吃饭
 * 坐车要求10个员工到上车,才能发车
 */
public class CyclicBarrierDemo03 {
    public static CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

    public static class CyclicBarrierTask extends Thread {
        int sleep;

        public CyclicBarrierTask(String name, int sleep) {
            super(name);
            this.sleep = sleep;
        }

        //等待吃饭
        void eat() {
            try {
                //模拟休眠
                TimeUnit.SECONDS.sleep(sleep);
                long starTime = System.currentTimeMillis();
                System.out.println(this.getName() + "到了,开始等待其他员工到座");
                //调用await()的时候,当前线程将会被阻塞,需要等待其他员工都到达await了才能继续
                cyclicBarrier.await();

                long endTime = System.currentTimeMillis();

                //休眠sleep时间,模拟当前员工吃饭耗时
                TimeUnit.SECONDS.sleep(sleep);

                System.err.println(this.getName() + ",sleep:" + this.sleep + " 等待了" + (endTime - starTime) + "(ms),开始吃饭了!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

        //等待所有人到齐之后,开车去下一站
        void drive() {
            try {
                long starTime = System.currentTimeMillis();
                //调用await()的时候,当前线程将会被阻塞,需要等待其他员工都到达await了才能继续
                cyclicBarrier.await();
                long endTime = System.currentTimeMillis();
                System.out.println(this.getName() + ",sleep:" + this.sleep + " 等待了" + (endTime - starTime) + "(ms),去下一景点的路上!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            //等待所有人到齐之后吃饭,先到的人坐那等着,什么事情不要干
            this.eat();
            //等待所有人到齐之后开车去下一景点,先到的人坐那等着,什么事情不要干
            this.drive();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 10; i++) {
            new CyclicBarrierTask("员工" + i, i).start();
        }
    }
}

二、运行截图

三、总结

        代码中CyclicBarrier相当于使用了2次,第一次用于等待所有人到达后开饭,第二次用于等待所有人上车后驱车去下一景点。

        CyclicBarrier内部相当于有个计数器(构造方法传入的),每次调用await();后,计数器会减1,并且await()方法会让当前线程阻塞,等待计数器减为0的时候,所有在await()上等待的线程被唤醒,然后继续向下执行,此时计数器又会被还原为创建时的值,然后可以继续再次使用

;