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()上等待的线程被唤醒,然后继续向下执行,此时计数器又会被还原为创建时的值,然后可以继续再次使用。