1、CyclicBarrier简介:
栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。
简单点:循环的CountDownLatch(倒数定时器),可以使用的同样的倒计时间的等待批量线程执行完成(可以多次)
2、CyclicBarrier代码:
1)模拟10个士兵先进行集合(10个线程先进行一次倒计时),所有人集合完成,打印"【司令】:士兵10个,集合完毕!"
2)然后进行各自任务的执行(10个线程再进行一次倒计时),等到所有的任务完成,打印"【司令】:士兵10个,任务完成!"
public class CyclicBarrierRunable implements Runnable{
// 1、模拟最终的任务执行命令
private boolean flag = Boolean.FALSE;
private int count = 10;
public CyclicBarrierRunable(boolean flag, int count) {
this.flag = flag;
this.count = count;
}
@Override
public void run() {
if (flag){
System.out.println("【司令】:士兵"+count+"个,任务完成!");
}else{
System.out.println("【司令】:士兵"+count+"个,集合完毕!");
flag = Boolean.TRUE;
}
}
// 2、模拟士兵线程操作
public static class SoliderRunable implements Runnable {
private String solider;
private CyclicBarrier cyclicBarrier;
public SoliderRunable(String solider, CyclicBarrier cyclicBarrier) {
this.solider = solider;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
// 等待所有士兵到齐
doCollection();
cyclicBarrier.await();
// 等待所有士兵完成任务
doWork();
cyclicBarrier.await();
}catch (InterruptedException e){
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public void doCollection(){
try {
Thread.sleep(Math.abs(new Random().nextInt()%10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--------->>>"+solider+"集合完毕");
}
public void doWork(){
try {
Thread.sleep(Math.abs(new Random().nextInt()%10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--------->>>"+solider+"任务完成");
}
}
// 3、线程模拟
public static void main(String[] args) {
final int N = 10; // 模拟10个士兵
boolean falg = Boolean.FALSE;
Thread[] allSolider = new Thread[N];
CyclicBarrier cyclicBarrier = new CyclicBarrier(N, new CyclicBarrierRunable(falg,N));
// 设置屏障点,主要是为了执行这个方法
System.out.println("【司令】:士兵集合!");
for (int i = 0; i < N; i++) {
allSolider[i] = new Thread(new SoliderRunable("士兵"+i,cyclicBarrier));
allSolider[i].start();
}
}
}
![1096351-f2ea5373e5d3b263.png](https://upload-images.jianshu.io/upload_images/1096351-f2ea5373e5d3b263.png)
3、CyclicBarrier代码解析:
CyclicBarrier cyclicBarrier = new CyclicBarrier(N, new CyclicBarrierRunable(falg,N));
即:为了执行后台的打印,我安装了10个前置线程操作
Thread[] allSolider = new Thread[N];
for (int i = 0; i < N; i++) {
allSolider[i] = new Thread(new SoliderRunable("士兵"+i,cyclicBarrier));
allSolider[i].start();
}
创建了SoliderRunable的线程会因为cyclicBarrier设置的10个前置线程进行任务执行,10个线程执行完后调用cyclicBarrier.await();进行cyclicBarrier主方法的执行!
4、CyclicBarrier只是用一次计时器(简化版):
1)模拟3个线程进行等待操作
2)等待完成之后,进行线程执行
public class CyclicBarrierRunable2 {
// 自定义工作线程
private static class Worker extends Thread {
private CyclicBarrier cyclicBarrier;
public Worker(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
super.run();
try {
// 让其他线程进行等待
doWait();
cyclicBarrier.await();
// 执行所有线程
doWork();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doWork(){
try {
System.out.println("--------->>>"+Thread.currentThread().getName() + "开始执行");
Thread.sleep(Math.abs(new Random().nextInt()%10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--------->>>"+Thread.currentThread().getName() + "执行完毕");
}
public void doWait(){
try {
System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
Thread.sleep(Math.abs(new Random().nextInt()%10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int threadCount = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
for (int i = 0; i < threadCount; i++) {
Worker worker = new Worker(cyclicBarrier);
worker.start();
}
}
}
![1096351-a8809dbb621599f1.png](https://upload-images.jianshu.io/upload_images/1096351-a8809dbb621599f1.png)
5、CyclicBarrier只是用一次计时器,代码解析:
CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
没有创建后面的Runable对象,仅仅使用cyclicBarrier的计时器,
cyclicBarrier.await();
只使用了一次的线程等待,如果使用多次参考上面的操作
6、使用总结:
1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。