1.JAVA多线程(十三)Java多线程之CyclicBarrier
CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。
1.1 CyclicBarrier类
CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。
- CyclicBarrier是一种同步机制,它可以使得一组线程在同一个障碍点进行等待。
- CyclicBarriers 可以通过重置计数器从而重新使用。
- CyclicBarrier支持一个可选的Runnable命令(实例化构造函数中的参数),该命令在最后一个线程到达后,但在任何线程被释放之前被执行。这一命令在barrier处只会被执行一次,且由最后到达的线程完成。这种屏障行为对于在任何一方继续之前更新共享状态都很有用。
- all-or-none破损模型:如果一个线程因为中断(or执行过程的失败,超时等)过早的离开了barrier点,那么等待在barrier点的其他所有线程也会在同一时间因为BrokenBarrierException或者InterruptedException异常而离开barrier。
内存一致性影响: -
- 线程在调用await()方法之前的行为要优先于barrier action中的任何行为。
-
- barrier action成功返回这一行为要优先于所有其他等待线程await()后的行为。
1.2 CyclicBarrier示例
package com.yuanxw.chapter13;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
/**
* CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。
* 它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
* CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
*/
public class CyclicBarrierExample {
private static volatile boolean isRunning = true;
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
isRunning = false;
System.out.println("任务执行结束后,回调函数!!!");
}
});
/** 线程-A **/
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(20);
System.out.println(String.format("线程【%s】执行完成", Thread.currentThread().getName()));
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"Thread-A").start();
/** 线程-A **/
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(String.format("线程【%s】执行完成", Thread.currentThread().getName()));
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"Thread-B").start();
while (isRunning) {
System.out.println(String.format("当前正在等待数量:【%s】", cyclicBarrier.getNumberWaiting()));
System.out.println(String.format("正在等待所需数量:【%s】 ", cyclicBarrier.getParties()));
System.out.println(String.format("中断或超时:【%s】", cyclicBarrier.isBroken()));
TimeUnit.SECONDS.sleep(5);
}
}
}
执行结果:
当前正在等待数量:【0】
正在等待所需数量:【2】
中断或超时:【false】
当前正在等待数量:【0】
正在等待所需数量:【2】
中断或超时:【false】
线程【Thread-B】执行完成
当前正在等待数量:【1】
正在等待所需数量:【2】
中断或超时:【false】
当前正在等待数量:【1】
正在等待所需数量:【2】
中断或超时:【false】
线程【Thread-A】执行完成
任务执行结束后,回调函数!!!
1.3 CyclicBarrier 和 CountDownLatch 的区别
- CountDownLatch 是计数器,只能使用一次,而 CyclicBarrier 的计数器提供 reset 功能,可以多次使用。
- 对于 CountDownLatch 来说,重点是“一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待。而对于 CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待。
- CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而 CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。
– 以上为《JAVA多线程(十三)Java多线程之CyclicBarrier》,如有不当之处请指出,我后续逐步完善更正,大家共同提高。谢谢大家对我的关注。
——厚积薄发(yuanxw)
来源:CSDN
作者:在天庭当托塔李天王的日子
链接:https://blog.csdn.net/yuan_xw/article/details/103994344