这应该是gitchat上面一个列子,讲到多线程并发控制。找不到出处了。如有侵权什么的 请联系我立马删除,个人觉得很形象生动通俗易懂,值得分享。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class SummonDragonDemo {
private static final int THREAD_COUNT_NUM = 7;
private static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT_NUM);
public static void main(String[] args) {
//设置第一个屏障点,等待召集齐7位法师
CyclicBarrier callMasterBarrier = new CyclicBarrier(THREAD_COUNT_NUM, ()-> {
System.out.println("7个法师召集完毕,同时出发,去往不同地方寻找龙珠!");
summonDragon();
});
//召集齐7位法师
for (int i = 1; i <= THREAD_COUNT_NUM; i++) {
int index = i;
new Thread(() -> {
try {
System.out.println("召集第" + index + "个法师");
callMasterBarrier.await();
} catch ( Exception e) {
e.printStackTrace();
}
}).start();
}
}
/**
* 召唤神龙:1、收集龙珠;2、召唤神龙
*/
private static void summonDragon() {
//设置第二个屏障点,等待7位法师收集完7颗龙珠,召唤神龙
CyclicBarrier summonDragonBarrier = new CyclicBarrier(THREAD_COUNT_NUM, new Runnable() {
@Override
public void run() {
System.out.println("集齐七颗龙珠!召唤神龙!");
}
});
//收集7颗龙珠
for (int i = 1; i <= THREAD_COUNT_NUM; i++) {
int index = i;
new Thread(() -> {
try {
System.out.println("第" + index + "颗龙珠已收集到!");
summonDragonBarrier.await();
} catch ( Exception e) {
e.printStackTrace();
}
}).start();
}
}
public static void zh() throws InterruptedException {
for (int i = 1; i <= THREAD_COUNT_NUM; i++) {
int index = i;
new Thread(() -> {
try {
System.out.println("第" + index + "颗龙珠已收集到!");
//模拟收集第i个龙珠,随机模拟不同的寻找时间
Thread.sleep(new Random().nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
//每收集到一颗龙珠,需要等待的颗数减1
countDownLatch.countDown();
}).start();
}
//等待检查,即上述7个线程执行完毕之后,执行await后边的代码
countDownLatch.await();
System.out.println("集齐七颗龙珠!召唤神龙!");
}
}
召集第2个法师
召集第6个法师
召集第5个法师
召集第4个法师
召集第1个法师
召集第7个法师
召集第3个法师
7个法师召集完毕,同时出发,去往不同地方寻找龙珠!
第1颗龙珠已收集到!
第2颗龙珠已收集到!
第3颗龙珠已收集到!
第4颗龙珠已收集到!
第5颗龙珠已收集到!
第6颗龙珠已收集到!
第7颗龙珠已收集到!
集齐七颗龙珠!召唤神龙!
CyclicBarrier 和 CountDownLatch 的区别
CountDownLatch 的计数器只能使用一次。而 CyclicBarrier 的计数器可以使用 reset() 方法重置。所以 CyclicBarrier 能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
CyclicBarrier 还提供其他有用的方法,比如 getNumberWaiting 方法可以获得 CyclicBarrier 阻塞的线程数量。isBroken 方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回 true。
CountDownLatch 会阻塞主线程,CyclicBarrier 不会阻塞主线程,只会阻塞子线程。