1、在做leetcode中H2O 生成题目时用到了CyclicBarrier,于是尝试写了以下代码:
- package utils;
-
- import java.util.concurrent.CyclicBarrier;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.atomic.AtomicInteger;
-
- public class H2O {
- private CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
- @Override public void run() {
- System.out.println("|");
- cb.reset();
- }
- });
-
- private int count = 5;
-
- public void pintH2O(){
- ExecutorService executorService = Executors.newFixedThreadPool(3);
- executorService.execute(new Runnable() {
- @Override public void run() {
- for(int i = 0; i < count; i++){
- System.out.print('H');
- try{
- cb.await();
- } catch (Exception e){
- System.out.print(" 1error " + e.toString());
- }
- }
- }
- });
-
- executorService.execute(new Runnable() {
- @Override public void run() {
- for(int i = 0; i < count; i++){
- System.out.print('H');
- try{
- cb.await();
- } catch (Exception e){
- System.out.print(" 2error " + e.toString());
- }
- }
- }
- });
-
- executorService.execute(new Runnable() {
- @Override public void run() {
- for(int i = 0; i < count; i++){
- System.out.print('O');
- try{
- cb.await();
- } catch (Exception e){
- System.out.print(" 3error " + e.toString());
- }
- }
- }
- });
-
- executorService.shutdown();
-
- }
- }
2、执行后产生了如下结果
- HHO|
- O 1error java.util.concurrent.BrokenBarrierExceptionH 2error java.util.concurrent.BrokenBarrierExceptionH|
- H 3error java.util.concurrent.BrokenBarrierExceptionO 1error java.util.concurrent.BrokenBarrierExceptionH|
- H 3error java.util.concurrent.BrokenBarrierExceptionO 1error java.util.concurrent.BrokenBarrierExceptionH|
- H 2error java.util.concurrent.BrokenBarrierExceptionH 3error java.util.concurrent.BrokenBarrierExceptionO|
- 1error java.util.concurrent.BrokenBarrierException 2error java.util.concurrent.BrokenBarrierException
- Process finished with exit code 0
3、在stackoverflow中发现了相同的问题Why CyclicBarrier reset() method is throwing BrokenBarrierException
原因如下:
(1)执行reset时,如果有线程正在等待屏障,则此线程会抛出BrokenBarrierException
(2)CyclicBarrier初始化时配置的Runnable(barrierAction),会在所有线程突破屏障后,由最后一个到达的线程去执行,这就解释了为什么第一次没有线程抛BrokenBarrierException,而后每次都另外2个线程抛出异常
(3)直观看来,reset做了2件事情:1、突破当前屏障;2、生成一个新屏障
(4)在查看以下源码后发现:无论是reset还是屏障被突破,都会生成一个新的generation instance,所以在循环中时不必调用reset,一般情况下也用不到此方法,上述代码把reset去掉即可正常执行
- public class CyclicBarrier {
- /**
- * Each use of the barrier is represented as a generation instance.
- * The generation changes whenever the barrier is tripped, or
- * is reset. There can be many generations associated with threads
- * using the barrier - due to the non-deterministic way the lock
- * may be allocated to waiting threads - but only one of these
- * can be active at a time (the one to which {@code count} applies)
- * and all the rest are either broken or tripped.
- * There need not be an active generation if there has been a break
- * but no subsequent reset.
- */
- private static class Generation {
- boolean broken = false;
- }
- ....
参考: