Why is CyclicBarrier reset () method throwing BrokenBarrierException

My goal is very simple. I want to use the method CyclicBarrier

and reset()

to run 3 threads 4 times using the code below. Explored all possible resources on the web, in Concurrency in practice and in thinking in Java. Couldn't solve as I want. Thinking in Java, there is one solution of this kind in HorseRace.Java, but it used the Executor service. I want to do this with methods CyclicBarrier

and reset()

. Here is my code along with an exit that continues to the end but throws BrokenBarrierException

after the reset () method.

package com.apal.barrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierEx1 {
    CyclicBarrier cb;
    public static int count = 0;

    public static void main(String[] args) {
        new CyclicBarrierEx1().manageThread();
    }

    private void manageThread() {
        cb = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                if (count == 3) {
                    System.out.println("Exit from system");
                    return;
                }
                System.out.println("Collating task");
                cb.reset();
                for (int i = 0; i < 3; i++) {
                    new Thread(new Worker(cb)).start();
                }
                count++;
            }
        });

        for (int i = 0; i < 3; i++) {
            new Thread(new Worker(cb)).start();
        }
    }
}

class Worker implements Runnable {
    CyclicBarrier cb;

    public Worker(CyclicBarrier cb) {
        this.cb = cb;
    }

    @Override
    public void run() {
        doSomeWork();
        try {
            cb.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    private void doSomeWork() {
        System.out.println("Doing some work ");
    }
}

      

Sample output

Doing some work 
Doing some work 
Doing some work 
Collating task
Doing some work 
Doing some work 
Doing some work 
Collating task
Doing some work 
java.util.concurrent.BrokenBarrierExceptionDoing some work 
Doing some work 
Collating task
Doing some work 

    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
    at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
    at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
Doing some work     at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)

    at java.lang.Thread.run(Unknown Source)
Doing some work 
Exit from systemjava.util.concurrent.BrokenBarrierException

    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
    at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
    at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
    at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
    at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
    at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
    at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
    at java.util.concurrent.CyclicBarrier.await(Unknown Source)
    at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
    at java.lang.Thread.run(Unknown Source)

      

+3


source to share


2 answers


You have a race condition where the barrier action is executed, which is passed in the constructor CyclicBarrier

. The docs forCyclicBarrier.await()

say about this method of action (emphasis mine):

If the current thread is the last thread, and a non-null barrier action was provided in the constructor, then the current thread starts the action before allowing other threads to continue .

This means that a call to the barrier action method reset()

cannot occur while these other threads are still waiting at the barrier. This will result in BrokenBarrierException

.



See the documentation for the paragraph that begins with "If the action of the barrier is independent of whether the parties are suspended when it is executed, then any thread in the batch can take that action when it is released." Using this method, you can perform the work that you are currently doing in an action routine within one of the worker threads as soon as it is freed from await()

. Below is an untested attempt (note - I also restarted where the variable is count

incremented to avoid a race condition in which worker threads might terminate before getting count

close to increasing):

package com.apal.barrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierEx1 {
    CyclicBarrier cb;
    public static int count = 0;

    public static void main(String[] args) {
        new CyclicBarrierEx1().manageThread();
    }

    public static void barrierComplete(CyclicBarrier cb) {
        System.out.println("Collating task");

        if (count == 3) {
            System.out.println("Exit from system");
            return;
        }
        count++;

        for (int i = 0; i < 3; i++) {
            new Thread(new Worker(cb)).start();
        }
    }

    private void manageThread() {
        cb = new CyclicBarrier(3);

        for (int i = 0; i < 3; i++) {
            new Thread(new Worker(cb)).start();
        }
    }
}


class Worker implements Runnable {
    CyclicBarrier cb;

    public Worker(CyclicBarrier cb) {
        this.cb = cb;
    }

    @Override
    public void run() {
        doSomeWork();
        try {
            if (cb.await() == 0) {
                CyclicBarrierEx1.barrierComplete(cb);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    private void doSomeWork() {
        System.out.println("Doing some work ");
    }
}

      

+2


source


Took an idea from MichaelBurr's tip to check for no pending number of threads in the worker thread before resetting the CyclicBarrier synchronizer. I am posting my own answer because I really wanted to use the CyclicBarrier and reset () method to achieve multiple threads starting and matching their tasks, such as Matrix manipulation.

package com.apal.barrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierEx1 {
    CyclicBarrier cb;
    public static int count = 0;

    public static void main(String[] args) {
        new CyclicBarrierEx1().manageThread();
    }

    private void manageThread() {
        cb = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                if (count == 3) {
                    System.out.println("Exit from system");
                    return;
                }
                System.out.println("Collating task");
                count++;
                // cb.reset();         **Commented and replaced in Worker**
                for (int i = 0; i < 3; i++) {
                    new Thread(new Worker(cb)).start();
                }
            }
        });

        for (int i = 0; i < 3; i++) {
            new Thread(new Worker(cb)).start();
        }
    }
}

class Worker implements Runnable {
    CyclicBarrier cb;

    public Worker(CyclicBarrier cb) {
        this.cb = cb;
    }

    @Override
    public void run() {
        doSomeWork();
        try {
            cb.await();
            //if (cb.getNumberWaiting() == 0) // **if no one is waiting, then reset it.**
            //  cb.reset();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    private void doSomeWork() {
        System.out.println("Doing some work ");
    }
}

      

Sample output

Doing some work 
Doing some work 
Doing some work 
Collating task
Doing some work 
Doing some work 
Doing some work 
Collating task
Doing some work 
Doing some work 
Doing some work 
Collating task
Doing some work 
Doing some work 
Doing some work 
Exit from system

      



From the Javadoc for reset ()

Resets the barrier to its original state. If any parties are currently waiting at the barrier, they will return with BrokenBarrierException. Note that resetting after a break occurs for other reasons may be difficult to complete; threads must re-sync in a different way and choose one to reset. It may be preferable to create a new barrier for later use.

So reset causes any currently waiting threads to throw a BrokenBarrierException and wake up immediately. reset is used when you want to "break" the barrier.

You cannot use reset () under normal circumstances.

0


source







All Articles