CyclicBarrier和CountDownLatch区别
参考CyclicBarrier和CountDownLatch区别
读完上边
的分析后,按照自己的理解,写个demo
场景:
有一辆列车A8888 从始发地开往北京
途中,收到了列车调度室的让道指令
需要暂时让道2辆动车驶过先
待收到重新启动命令后,再行启动重新出发
- CountDownLatch
代码:
import java.util.concurrent.CountDownLatch;
/**
* usage:multy thread ,count down latch(tanhuang lock)
*
* @author W
* @version Id: CountDownLatchTest.java , 2018/07/27 14:28 W Exp $$
*/
public class CountDownLatchTest {
private static final int YouFirstThreadCount = 2;//需要让道的动车辆数
static CountDownLatch countDownLatch = new CountDownLatch(YouFirstThreadCount);
//Latch read [lætʃ]
public static void main(String args[]) throws InterruptedException {
System.out.println("普列A8888号启动开往北京.....\n");
System.out.println("\n调度室指令:\n\t\t请普列A8888号让道其他列车行驶...");
System.out.println("\n普列A8888号准备让道其他动车....\n");
toLetOtherFirst();
System.out.println("\n普列A8888号准备重新启动开往北京....");
}
private static void toLetOtherFirst() throws InterruptedException {
for (int i=0;i<countDownLatch.getCount();i++){
new Thread(new ReadNum(i,countDownLatch)).start();
}
countDownLatch.await();
}
static class ReadNum implements Runnable{
private int id;
private CountDownLatch latch;
public ReadNum(int id,CountDownLatch latch) {
this.id=id;
this.latch = latch;
}
@Override
public void run() {
synchronized(this){
System.out.println("动车"+(id+1)+"号已开过让车地....");
latch.countDown();
if ( latch.getCount() == 0) {
System.out.println("\n调度室指令:\n\t\t受让车数量为0,已完成让道任务,请继续启动行车...");
}
}
}
}
}
输出结果:
普列A8888号启动开往北京.....
调度室指令:
请普列A8888号让道其他列车行驶...
普列A8888号准备让道其他动车....
动车1号已开过让车地....
动车2号已开过让车地....
调度室指令:
受让车数量为0,已完成让道任务,请继续启动行车...
普列A8888号准备重新启动开往北京....
Process finished with exit code 0
从上边可以看出,列车A8888(可以理解成主线程),其他动车(其他线程)
共同形成多线程环境
待动车组(2辆)先行开过,这个为先行事件 threads.start()
先行事件启动后,列车A8888开始进入等待阻塞状态 latch.await()
thread内部run完后,latch.countDown();//超过一辆,计算一辆
当 latch.getCount() == 0 ,列车会从await态到唤醒状态
整个过程就是这样子
CountDownLatch 0时释放所有等待的线程,计数为0时,无法重置,不可重复利用
- CyclicBarrier
代码:
import java.util.concurrent.CyclicBarrier;
/**
* 循环
*
* @author W
* @version Id: CyclicBarrierTest.java , 2018/07/27 15:07 W Exp $$
*/
public class CyclicBarrierTest {
private static final int YouFirstThreadCount = 4;//需要让道的动车辆数
static CyclicBarrier cyclicBarrier = new CyclicBarrier(YouFirstThreadCount,new Runnable() {
@Override
public void run() {
System.out.println("\n调度室指令:\n\t\t受让车数量"+cyclicBarrier.getParties()+"辆,已完成让道任务,请继续启动行车...");
System.out.println("\n普列A8888号准备重新启动开往北京....\n");
}
});
public static void main(String[] args) throws InterruptedException {
System.out.println("普列A8888号启动开往北京.....\n");
System.out.println("\n调度室指令:\n\t\t请普列A8888号让道其他列车行驶...");
System.out.println("\n普列A8888号准备让道其他动车....\n");
for (int i = 0; i < cyclicBarrier.getParties(); i++) {
new Thread(new readNum(i,cyclicBarrier)).start();
}
//CyclicBarrier 可以重复利用,
//这个是CountDownLatch做不到的
/*for (int i = 10; i < 10+cyclicBarrier.getParties(); i++) {
new Thread(new readNum(i,cyclicBarrier)).start();
}*/
}
static class readNum implements Runnable{
private int id;
private CyclicBarrier cyc;
public readNum(int id,CyclicBarrier cyc){
this.id = id;
this.cyc = cyc;
}
@Override
public void run() {
synchronized (this){
try {
System.out.println("动车"+(id+1)+"号已开过让车地....");
cyc.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
输出结果:
普列A8888号启动开往北京.....
调度室指令:
请普列A8888号让道其他列车行驶...
普列A8888号准备让道其他动车....
动车1号已开过让车地....
动车2号已开过让车地....
动车4号已开过让车地....
动车3号已开过让车地....
调度室指令:
受让车数量4辆,已完成让道任务,请继续启动行车...
普列A8888号准备重新启动开往北京....
Process finished with exit code 0
从输出结果看,CyclicBarrier照样可以实现CountDownLatch功能
使用上的区别:
1
- CountDownLatch 做减法计算,count=0,唤醒阻塞线程
- CyclicBarrier 做加法计算,count=屏障值(parties),唤醒阻塞线程
2
- CyclicBarrier 比 CountDownLatch 更灵活,计数达到指定值时,计数置为0重新开始,可重复利用,还有个reset方法可使用
我们知道主线程执行,比Thread.start();里头的run()方法在时间上更快一些
为了确保某些定时任务或者特定的任务方法先执行完,再执行主线程,就可以这么干了.