Vasu
Vasu

Reputation: 22422

java CyclicBarrier not broken with reset

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

Answers (2)

dcernahoschi
dcernahoschi

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

passion
passion

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

Related Questions