Reputation: 22422
I am trying to test BrokenBarrierException by resetting the cyclicbarrier in the middle of starting (awaiting) few parties (threads), please find the below sample code for the same.
User class:
public class User implements Runnable {
private final String name;
private final CyclicBarrier cb;
public User(String name, CyclicBarrier cb) {
this.name = name;
this.cb = cb;
}
@Override
public void run() {
System.out.println(name+" user started !!!! ");
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
System.out.println(e);
e.printStackTrace();
}
}
}
CyclicBarrierTest class:
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(5);
User user1 = new User("USER1", barrier);
new Thread(user1).start();
User user2 = new User("USER2", barrier);
new Thread(user2).start();
//Expected users are 5, but only 2 user threads started so far
// and resetting below which should throw barrier broken exception
barrier.reset();
if(barrier.isBroken()) {
System.out.println("Barrier broken ");
}
}
}
So, after running the main() above, I could get any exceptions and also "Barrier broken" also not printed. The threads are simply waiting.
I have referred the CyclicBarrier API below link:
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html
public void reset():
Resets the barrier to its initial state. If any parties are currently waiting at the barrier, they will return with a BrokenBarrierException.
But my above code doesn't seems to work according to the API description, so what is the problem with my above code and why it is NOT throwing BrokenBarrierException ?
Could you please help ?
Upvotes: 2
Views: 1025
Reputation: 15240
Short answer:
On reset the barrier loses the information of previous BrokenBarrierException
(s). So any call to isBroken
after reset
will return false
.
The javadoc specify this, although, not very clearly:
isBroken
return: true if one or more parties broke out of this barrier due to interruption or timeout since construction or the last reset, or a barrier action failed due to an exception; false otherwise.
Long answer:
You can see more clearly what happens if you look at source code of reset
and isBroken
:
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
private static class Generation {
boolean broken = false;
}
public boolean isBroken() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return generation.broken;
} finally {
lock.unlock();
}
}
You can see that the reference generation.broken
holds the information about a broken barrier. But this is reinitialized to false
on reset.
Upvotes: 1
Reputation: 1360
If you want exception thrown , you have to make sure barrier.reset();
executes after cb.await();
, but here System.out.println(name+" user started !!!! ");
is a very costly statement which makes barrier.reset();
executes too early , you can add a sleep statement before barrier.reset();
, say Thread.sleep(100);
.
Doc of isBroken
:
true if one or more parties broke out of this barrier due to interruption or timeout since construction or the last reset, or a barrier action failed due to an exception; false otherwise.
If you want it as broken , you can do something to the parties . You need remove reset
to make threads awaiting .
public class User implements Runnable {
private final String name;
private final CyclicBarrier cb;
public User(String name, CyclicBarrier cb) {
this.name = name;
this.cb = cb;
}
@Override
public void run() {
System.out.println(name+" user started !!!! ");
try {
cb.await(1,TimeUnit.SECONDS);
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+" user ended !!!! ");
}
}
public class CyclicBarrierTest {
public static void main(String[] args) throws Exception {
CyclicBarrier barrier = new CyclicBarrier(5);
User user1 = new User("USER1", barrier);
new Thread(user1).start();
User user2 = new User("USER2", barrier);
new Thread(user2).start();
//Expected users are 5, but only 2 user threads started so far
// and resetting below which should throw barrier broken exception
Thread.sleep(100);
// barrier.reset();
Thread.sleep(1100);
if(barrier.isBroken()) {
System.out.println("Barrier broken ");
}
}
}
Upvotes: 1