写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!
概念:
CyclicBarrier允许一组线程在到达某个栅栏点(common barrier point)互相等待,直到最后一个线程到达栅栏点,栅栏才会打开,处于阻塞状态的线程恢复继续执行。通过CyclicBarrier的await()方法,线程就处于barrier状态。找到一张动图很好的说明了CyclicBarrier的执行过程。
常用构造方法:
1.public CyclicBarrier(int parties)
初始化相互等待的线程数量。
2.public CyclicBarrier(int parties, Runnable barrierAction)
初始化相互等待的线程数量以及屏障线程。
参数说明:
parties:表示一起执行的线程个数,例如:CyclicBarrier cyclicBarrier = new CyclicBarrier(3);于是拥有CyclicBarrier对象的线程当 parties的计数为3时就会唤醒,这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加1,一直加到初始的值。
Runnable barrierAction:
表示线程都处于barrier时,一起执行之前,先执行的一个线程,即:屏障线程的运行时机:等待的线程数量=parties之后,CyclicBarrier打开屏障之前。这个参数是一个实现Runnable接口的类的对象 。
常用方法:
await(): 在CyclicBarrier上进行阻塞等待,直到
1): 在CyclicBarrier上等待的线程数达到parties,则所有线程释放,继续执行。
2): 当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。
3): 其它等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
4): 其它等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
5): 其它线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
await(timeout,TimeUnit): 在CyclicBarrier上进行限时的阻塞等待,直到
1): 同上五条。
2): 当前线程等待超时,则抛出TimeoutException异常,并停止等待,继续执行。
getParties(): 获取CyclicBarrier打开屏障的线程数量。
getNumberWaiting(): 获取正在CyclicBarrier上等待的线程数量。
reset(): 使得CyclicBarrier回归初始状态。
1): 如果有正在等待的线程,则会抛出BrokenBarrierException异常,且这些线程停止等待,继续执行。
2): 将是否破损标志位broken置为false。
isBroken(): 获取是否破损标志位broken的值,此值有以下几种情况:
1): CyclicBarrier初始化时,broken=false,表示屏障未破损。
2): 如果正在等待的线程被中断,则broken=true,表示屏障破损。
3): 如果正在等待的线程超时,则broken=true,表示屏障破损。
4): 如果有线程调用CyclicBarrier.reset()方法,则broken=false,表示屏障回到未破损状态。
场景:
1.以相约爬山为例,三个小伙伴都到了,然后再开始爬上。
2.以相约爬山为例,三个小伙伴都到了,然后一起喊了一声加油,然后再开始爬上。
场景一代码示例:
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
for (int i=0;i<3;i++){
Task1 task1 = new Task1(cyclicBarrier);
executorService.execute(task1);
}
// 关闭线程池
executorService.shutdown();
}
static class Task1 implements Runnable{
private CyclicBarrier cyclicBarrier;
public Task1(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println("小伙伴" + Thread.currentThread().getName() + ":到了");
cyclicBarrier.await();
System.out.println("开始爬山!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
执行结果如下:
场景二代码示例:
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
CyclicBarrier cyclicBarrier1 = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("加油!");
}
});
for (int i=0;i<3;i++){
Task1 task1 = new Task1(cyclicBarrier1);
executorService.execute(task1);
}
// 关闭线程池
executorService.shutdown();
}
static class Task1 implements Runnable{
private CyclicBarrier cyclicBarrier;
public Task1(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println("小伙伴" + Thread.currentThread().getName() + ":到了");
cyclicBarrier.await();
System.out.println("开始爬山!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
执行结果如下:
结合前面的CountDownLatch对比一下它们的区别:
1.CountDownLatch是线程组之间的等待,即一个(或多个)线程等待N个线程完成某件事情之后再执行;而CyclicBarrier则是线程组内的等待,即每个线程相互等待,即N个线程都被拦截之后,然后依次执行。
2.CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。
3.CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置。
4.CountDownLatch不可以复用,而CyclicBarrier可以复用。