1、在做leetcode中H2O 生成题目时用到了CyclicBarrier,于是尝试写了以下代码:
java
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、执行后产生了如下结果
java
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去掉即可正常执行
java
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;
}
....
参考: