CountDownLatch和CyclicBarrier用法及例子
1.都是用来实现其他任务都完成后,然后再执行一个任务的需求,类似赛跑比赛,需要等所有运动员到达终点后,才能开始下一步颁奖。
2.CountDownLatch是一次性的,不能重复使用;CyclicBarrier是可重复的;
3.CountDownLatch使用时,在每个需要等待的地方调用await,在每个触发条件的地方调用countDown即可,countDown次数达到指定次数,会唤醒所有await;
4.CyclicBarrier使用时,在每个需要等待的地方调用await,然后内部会自动统计await次数,到达指定次数后,自动回调,完成回调后,唤醒所有await。
例子1,每个任务计算一个值,都完成计算后进行下一步计算。Test2模拟了普通的计算任务,都完成后,会从latch.await()那个地方继续执行:
public class Main {
private static final int N = 5;
public static final void main(String[] args) {
testCountDownLatch();
}
private static void testCountDownLatch() {
CountDownLatch latch = new CountDownLatch(N);
Test2[] tt = new Test2[N];
for (int i = 0; i < N; i++) {
tt[i] = new Test2(latch);
new Thread(tt[i]).start();
}
System.out.println("Main is Wait.");
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int total = 0;
for (int i = 0; i < N; i++) {
total += tt[i].ret;
}
System.out.println("Main is Wait Over!" + total);
}
}
public class Test2 implements Runnable {
private CountDownLatch latch;
public Test2(CountDownLatch latch) {
this.latch = latch;
}
public int ret = 0;
@Override
public void run() {
System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ret = 1;
System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
latch.countDown();
}
}
输出结果:
Thread-Thread-1 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is Running
Main is Wait.
Thread-Thread-4 is Running
Thread-Thread-0 is Running
Thread-Thread-2 is finish Task!
Thread-Thread-4 is finish Task!
Thread-Thread-3 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Main is Wait Over!5
例子2,用CountDownLatch实现的一个运动员比赛的程序:
public class Main {
// 运动员数量
private static final int N = 5;
public static final void main(String[] args) {
testCountDownLatch2();
}
private static void testCountDownLatch2() {
// 运动员准备好的信号
CountDownLatch latchStart = new CountDownLatch(N);
// 运动员都完成比赛的信号
CountDownLatch latchOver = new CountDownLatch(N);
// 正式开始比赛的信号
CountDownLatch startSignal = new CountDownLatch(1);
for (int i = 0; i < N; i++) {
new Thread(new Player(i, latchStart, latchOver, startSignal)).start();
}
System.out.println("等待运动员都准备好");
try {
// 等待运动员都准备好
latchStart.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开始比赛");
// 开始比赛信号
startSignal.countDown();
try {
// 等待所有运动员完成比赛
latchOver.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有运动员都完成了比赛,比赛结束");
}
}
public class Player implements Runnable {
private CountDownLatch latchStart;
private CountDownLatch latchOver;
private CountDownLatch startSignal;
private int id;
private static Random sRandom = new Random();
public Player(int id, CountDownLatch latchStart, CountDownLatch latchOver, CountDownLatch startSignal) {
this.id = id;
this.latchStart = latchStart;
this.latchOver = latchOver;
this.startSignal = startSignal;
}
@Override
public void run() {
// 模拟准备时间
try {
Thread.sleep(sRandom.nextInt(2000));
} catch (InterruptedException e2) {
e2.printStackTrace();
}
System.out.println("Player" + id + "准备好" + System.currentTimeMillis());
// 运动员准备好
this.latchStart.countDown();
try {
// 等待裁判说开始
this.startSignal.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("Player" + id + " 开始跑" + System.currentTimeMillis());
long duration = sRandom.nextInt(5000);
try {
// 模拟跑的时间
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Player" + id + " 完成比赛,耗时:" + duration);
// 运动员完成比赛
this.latchOver.countDown();
}
}
输出结果:
等待运动员都准备好
Player0准备好1508221461341
Player2准备好1508221461832
Player3准备好1508221462335
Player4准备好1508221462369
Player1准备好1508221463031
开始比赛
Player0 开始跑1508221463032
Player4 开始跑1508221463032
Player3 开始跑1508221463032
Player2 开始跑1508221463032
Player1 开始跑1508221463032
Player1 完成比赛,耗时:1202
Player2 完成比赛,耗时:1939
Player0 完成比赛,耗时:1947
Player4 完成比赛,耗时:2878
Player3 完成比赛,耗时:3974
所有运动员都完成了比赛,比赛结束
例子3,用CyclicBarrier实现例子1:
public class Main {
private static final int N = 5;
public static final void main(String[] args) {
testCyclicBarrier();
}
private static void testCyclicBarrier() {
Test3[] tt = new Test3[N];
CyclicBarrier barrier = new CyclicBarrier(N, new Runnable() {
@Override
public void run() {
// await达到指定次数,随机选一个线程来执行这个任务
System.out.println("Barrier All Task Finished,CurrentThread=" + Thread.currentThread().getName());
int total = 0;
for (int i = 0; i < N; i++) {
total += tt[i].ret;
}
System.out.println("计算结果是:" + total);
}
});
for (int i = 0; i < N; i++) {
tt[i] = new Test3(barrier);
new Thread(tt[i]).start();
}
}
}
public class Test3 implements Runnable {
private CyclicBarrier barrier;
public Test3(CyclicBarrier barrier) {
this.barrier = barrier;
}
public int ret = 0;
@Override
public void run() {
System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ret = 1;
System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
try {
this.barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Thread-" + Thread.currentThread().getName() + " exit!");
}
}
输出结果:
Thread-Thread-1 is Running
Thread-Thread-0 is Running
Thread-Thread-3 is Running
Thread-Thread-4 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is finish Task!
Thread-Thread-2 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Thread-Thread-4 is finish Task!
Barrier All Task Finished,CurrentThread=Thread-4
计算结果是:5
Thread-Thread-4 exit!
Thread-Thread-3 exit!
Thread-Thread-0 exit!
Thread-Thread-1 exit!
Thread-Thread-2 exit!
例子4,用CyclicBarrier实现例子2:
public class Main {
private static final int N = 5;
public static final void main(String[] args) {
testCyclicBarrier2();
}
private static void testCyclicBarrier2() {
CyclicBarrier barrierPrepare = new CyclicBarrier(N, new Runnable() {
@Override
public void run() {
// 准备完成
System.out.println("所有运动员准备完毕,开始比赛");
}
});
CyclicBarrier barrierOver = new CyclicBarrier(N, new Runnable() {
@Override
public void run() {
// 比赛完成
System.out.println("所有运动员比赛都完成了,结束比赛");
}
});
for (int i = 0; i < N; i++) {
new Thread(new Player2(i, barrierPrepare, barrierOver)).start();
}
}
}
public class Player2 implements Runnable {
private CyclicBarrier barrierPrepared;
private CyclicBarrier barrierOver;
private int id;
private static Random sRandom = new Random();
public Player2(int id, CyclicBarrier barrierPrepared, CyclicBarrier barrierOver) {
this.barrierPrepared = barrierPrepared;
this.barrierOver = barrierOver;
this.id = id;
}
public void run() {
try {
// 模拟准备比赛
Thread.sleep(sRandom.nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("运动员" + id + "准备比赛");
try {
// 等待开始
barrierPrepared.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("运动员" + id + "开始比赛" + System.currentTimeMillis());
int duration = sRandom.nextInt(5000);
try {
// 模拟比赛耗时
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("运动员" + id + "完成比赛,比赛时长:" + duration);
try {
// 等待比赛结束
barrierOver.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
输出结果:
运动员2准备比赛
运动员0准备比赛
运动员1准备比赛
运动员4准备比赛
运动员3准备比赛
所有运动员准备完毕,开始比赛
运动员3开始比赛1508222334484
运动员2开始比赛1508222334484
运动员1开始比赛1508222334484
运动员0开始比赛1508222334484
运动员4开始比赛1508222334484
运动员4完成比赛,比赛时长:777
运动员0完成比赛,比赛时长:2640
运动员1完成比赛,比赛时长:2952
运动员3完成比赛,比赛时长:3843
运动员2完成比赛,比赛时长:3924
所有运动员比赛都完成了,结束比赛