Java高并发编程中CyclicBarrier的使用及详细介绍-刘宇
作者:刘宇
CSDN博客地址:https://blog.csdn.net/liuyu973971883
有部分资料参考,如有侵权,请联系删除。如有不正确的地方,烦请指正,谢谢。
一、什么是CyclicBarrier
“循环栅栏”,大概的意思就是一个可循环利用的屏障。它的作用就是会让所有线程都等待完成后才会继续下一步行动。打个比方,我们和好朋友约好出去吃饭的时候,有些人早到了,有些人晚到了,但是饭局要等到所有人都到了才能开始,且他们是相互监督的。我们可以把这些朋友看作一个线程。
二、CyclicBarrier的简单使用
1、构造方法
- parties:一个任务需要被分为几个子任务,即我们上述举例中的有几个朋友。
- barrierAction:所有子任务都完成后将会执行这个Runnable,即上述所说的吃饭
//构造函数1
public CyclicBarrier(int parties)
//构造函数2
public CyclicBarrier(int parties, Runnable barrierAction)
2、await()
- 调用该方法后,表示该线程已到达栅栏,等待其他线程
public int await() throws InterruptedException, BrokenBarrierException
3、await(long timeout, TimeUnit unit)
- 调用该方法后,表示该线程已到达栅栏,等待指定时间
- timeout:等待指定时间,如果还有线程未到达栅栏,那么也不再等了
- TimeUnit:时间单位
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
4、getParties()
- 获取该CyclicBarrier有几个部分,即初始化时候定义了几个部分
public int getParties()
5、isBroken()
- 判断栅栏是否被打破
public boolean isBroken()
6、getNumberWaiting()
- 获取当前await的线程有多少个
public int getNumberWaiting()
三、简单示例
package com.test.part3.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
public class CyclicBarrierExample {
public static void main(String[] args) {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
//当所有分支全部完成后回调
System.out.println("All threads finished");
}
});
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("T1 finished work");
//等待其他前程完成,如果都完成了将自动唤醒
cyclicBarrier.await();
System.out.println("T1 The other thread finished too");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("T2 finished work");
//等待其他前程完成,如果都完成了将自动唤醒
cyclicBarrier.await();
System.out.println("T2 The other thread finished too");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
}
输出结果:
T2 finished work
T1 finished work
All threads finished
T1 The other thread finished too
T2 The other thread finished too
四、什么时候会出现BrokenBarrierException异常
- 当我们调用reset方法对栅栏重新设置的时候就会出现BrokenBarrierException异常
package com.test.part3.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
public class CyclicBarrierExample2 {
public static void main(String[] args) throws InterruptedException {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
new Thread(new Runnable() {
@Override
public void run() {
try {
//休眠5秒
TimeUnit.SECONDS.sleep(5);
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
//立即await
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
//休眠100毫秒
TimeUnit.MILLISECONDS.sleep(100);
//进行重置,那么进入await的线程就会抛出BrokenBarrierException异常
cyclicBarrier.reset();
}
}
输出结果:
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
at com.test.part3.CyclicBarrier.CyclicBarrierExample2$2.run(CyclicBarrierExample2.java:28)
at java.lang.Thread.run(Thread.java:745)
五、CyclicBarrier和CountDownLatch的区别
他们都是可以实现当一组线程达到某个条件的时候再执行某些任务,是因为他们内部都有一个count计数器,当计数器为0时将所有阻塞的线程唤醒。
区别:
- CyclicBarrier的await会将线程进行阻塞并且将count值减1,CountDownLatch的await只会将线程阻塞,计数器减1需要调用countdown来执行。
- CyclicBarrier可以实现循环拦截,调用reset方法即可重置栅栏,而CountDownLatch只能拦截一次。
- CyclicBarrier在等待多个线程到达某一条件时,他们是线程间相互监督的。CountDownLatch并不是线程间相互监督,而是有个类似于裁判的角色进行管理的。