- CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行;
- CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。
对于CountDownLatch来说,重点是“一个线程(多个线程)等待”,而其他的N个线程在完成“某件事情”之后,可以终止,也可以等待。而对于CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须互相等待,然后继续一起执行。
CountDownLatch是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而CyclicBarrier更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。
CyclicBarrier介绍
-
CyclicBarrier(int parties) 默认构造方法,参数表示拦截的线程数量。这里的parties也是一个计数器,例如,初始化时parties里的计数是3,于是拥有该CyclicBarrier对象的线程当parties的计数为3时就唤醒,注:这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加1,一直加到初始的值
-
CyclicBarrier(int parties, Runnable barrierAction) 由于线程之前的调度是由CPU决定的,所以默认的构造方法无法设置线程执行优先级,CyclicBarrier提供一个更高级的构造函数
CyclicBarrier(int parties, Runnable barrierAction)
,用于在线程到达同步点时,优先执行线程barrierAction,这样可以更加方便的处理一些负责的业务场景。
使用案例如下:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
class Player implements Runnable {
private CyclicBarrier cyclicBarrier;
private int id;
public Player(int id, CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
this.id = id;
}
@Override
public void run() {
try {
System.out.println("玩家" + id + "第一关");
cyclicBarrier.await();//设置的四个,四个完成后才会执行后面的操作
System.out.println("玩家" + id + "进入第二关");
cyclicBarrier.await();
System.out.println("hahaha");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
@Override
public void run() {
//阻塞打开后才执行下面的操作
System.out.println("进入第二关");
}
});
for(int i = 0; i < 4; i++) {
new Thread(new Player(i, cyclicBarrier)).start();
}
}
}
输出打印:
玩家0第一关
玩家2第一关
玩家1第一关
玩家3第一关
进入第二关
玩家1进入第二关
玩家0进入第二关
玩家3进入第二关
玩家2进入第二关
进入第二关
hahaha
hahaha
hahaha
hahaha
CountDownLatch介绍
对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。
我们使用代码模拟这个过程,我们模拟了三个玩家,在三个玩家都准备好之后,游戏才能开始。代码的输出结果为:
正在等待所有玩家准备好
player0 已经准备好了, 所使用的时间为 2.402s
player2 已经准备好了, 所使用的时间为 2.415s
player3 已经准备好了, 所使用的时间为 2.552s
player1 已经准备好了, 所使用的时间为 2.84s
开始游戏
CountDownLatch的代码:
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class countdownlatch {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(4);
for(int i = 0; i < 4; i++) {
new Thread(new MyThread(latch), "player" + i).start();
}
System.out.println("正在等待所有玩家准备好");
latch.await();
System.out.println("开始游戏");
}
}
class MyThread implements Runnable {
private CountDownLatch latch;
public MyThread(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
Random rand = new Random();
int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
Thread.sleep(randomNum);
System.out.println(Thread.currentThread().getName()+" 已经准备好了, 所使用的时间为 "+((double)randomNum/1000)+"s");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
参考博客:
https://blog.csdn.net/liangyihuai/article/details/83106584
https://www.cnblogs.com/twoheads/p/9555867.html
https://blog.csdn.net/qweqwruio/article/details/81359780