CountDownLatch和CyclicBarrier
两个类都是java并发包java.util.concurrent中提供的控制线程的使用类。使用如下:
CountDownLatch的一个使用场景就是充当裁判的角色,等待
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(1);
CountDownLatch bizCdl = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
executorService.execute(new MySporter(cdl,bizCdl,"运动员"+i));
}
try {
//模拟准备时间
Thread.sleep(3000);
//发令
System.out.println("预备开始,啪");
cdl.countDown();
bizCdl.await();
System.out.println("等待所有运动员跑到终点后,开始统计成绩");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//释放资源
executorService.shutdown();
}
}
/**
*模拟运动员
*/
public class MySporter implements Runnable {
//主裁判
private CountDownLatch countDownLatch;
//运动员监控
private CountDownLatch bizCountDownlatch;
private String name;
public MySporter() {
}
public MySporter(CountDownLatch countDownLatch,CountDownLatch bizCountDownlatch,String name) {
this.countDownLatch = countDownLatch;
this.bizCountDownlatch=bizCountDownlatch;
this.name = name;
}
@Override
public void run() {
System.out.println("myname is "+name + " wait");
try {
//等待裁判吹开始哨
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"跑到终点了");
//跑到终点后,运动员监控跟着递减
bizCountDownlatch.countDown();
}
...
}
执行结果如下:
myname is 运动员0 wait
myname is 运动员1 wait
myname is 运动员2 wait
myname is 运动员3 wait
myname is 运动员4 wait
预备开始,啪
运动员1跑到终点了
运动员2跑到终点了
运动员3跑到终点了
运动员0跑到终点了
运动员4跑到终点了
等待所有运动员跑到终点后,开始统计成绩
CyclicBarrier是充当屏障的作用,等待所有的worker工作完成后,在同一个时刻集合,然后再进行后续的操作;代码如下:
public static void main(String[] args) {
int n = 4;
CyclicBarrier cb = new CyclicBarrier(n, new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "当前线程做后续的事情");
}
});
for (int l = 0; l < n; l++) {
new Thread(new Writer(cb)).start();
}
}
static class Writer implements Runnable {
private CyclicBarrier cb;
public Writer() {
}
public Writer(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "当前进程开始进行IO操作");
try {
//模拟io操作
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "执行完IO操作");
//等待其他线程
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "开始进行自己的业务操作");
}
}
执行结果如下:
Thread-0当前进程开始进行IO操作
Thread-1当前进程开始进行IO操作
Thread-2当前进程开始进行IO操作
Thread-3当前进程开始进行IO操作
Thread-2执行完IO操作
Thread-3执行完IO操作
Thread-1执行完IO操作
Thread-0执行完IO操作
Thread-0当前线程做后续的事情
Thread-0开始进行自己的业务操作
Thread-2开始进行自己的业务操作
Thread-1开始进行自己的业务操作
Thread-3开始进行自己的业务操作
从结果可以看出,当四个线程都到达品屏障后,会从四个线程中选择最后一个线程去执行CyclicBarrier中的Runnable操作。另外,barrier也是可以复用的。
总结:
区别 | CountDownLatch | CyclicBarrier |
---|---|---|
等待 | 1充当发令枪,触发子线程操作2等待所有子线程完成任务后,再执行主线程业务 | 一组线程互相等待 |
复用 | 不支持 | 支持 |