Java: CyclicBarrier – Explained

Oftentimes it’s necessary to write an application in which there are multiple threads that are mostly independent from one another, but require a sync up occasionally before proceeding. This is a great use case for a CyclicBarrier. It is called a Barrier because it prevents threads from proceeding, and it is called Cyclic because once all threads have reached the barrier, they are released and the barrier can then be reused, unlike latches.

Using a Barrier

There is a fixed number of threads that the Barrier will wait for before tripping and cycling over. The term usually used for this number is parties, as in a party of threads.

Using a barrier comes down to 2 steps:

  1. Create a barrier with a given ‘parties’ number
  2. Call await on that barrier (from a thread)

It’s important to note that all calls to await will block until the n’th call. Where n is the number specified when creating the barrier.

For this reason it is important that the number of threads coordinating with barrier is equal to or greater to the party number. If not, all threads will block and your application will never terminate. (At least not gracefully).

A Quick Example

Let’s imagine a scenario. There are group of 4 friends who love traveling. However, each friend will only travel from place to place via their preferred method of travel. In our group, we have a walker, a bus-rider, a train-taker, and a plane-passenger. The plane-passenger always arrives to the destination first, and the walker always gets there last, but they always meet up eventually.

Over the summer they decide to take a trip up the east coast of the United States to Montreal, Canada. During the trip, they will stop at these cities: Miami, Jacksonville, Washington, New York and Albany. To ensure everyone makes it safely, once one of the friends makes it to a city, he/she will wait until the others arrive. Then they will have a beer, sleep for the night, and head out the next day to the next city via their preferred method of travel.

The full code is below and then I’ll explain in more detail:

public class BarrierExample {

    //Trip up the east coast of the USA
    public static String[] locations = {"Miami", "Jacksonville", "Washington", 
                                        "New York", "Albany", "Montreal"};
    public static CyclicBarrier barrier;

    public static void main(String [] args) {
        Thread walker = new Thread(getRunnable("walker", 5));
        Thread bus = new Thread(getRunnable("bus", 4));
        Thread train = new Thread(getRunnable("train", 3));
        Thread plane = new Thread(getRunnable("plane", 2));
        barrier = new CyclicBarrier(4);

        walker.start();
        bus.start();
        train.start();
        plane.start();
    }

    public static Runnable getRunnable(final String type, final int secs) {
        return new Runnable() {
            public void run() {
                System.out.println("Thread " + type + " starting trip");
                for (int i = 0; i < locations.length; i++) {
                    System.out.println("Thread " + type + " leaving for " + locations[i]);
                    try {
                        Thread.sleep(secs * 1000); //simulates time it takes to travel
                        System.out.println("Thread " + type + " reached " + locations[i]);
                        System.out.println("Thread " + type + " waiting for others...");
                        barrier.await();
                    }
                    catch(InterruptedException ie) {
                        System.out.println("Thread " + type + " interrupted");
                    }
                    catch(BrokenBarrierException bbe) {
                        System.out.println("Barrier has been broken!");
                    }
                }
                System.out.println("Thread " + type + " finished trip!");
            }
        };
    }
}

Defining our Runnables

In this example, each friend is represented as a Runnable:

public static Runnable getRunnable(final String type, final int secs) {

The type parameter is mostly used for identification purposes. The secs parameter is provided to make our threads sleeps for the specified period. This allows us to simulate the time it takes to travel by that medium. In our case, the plane is the fastest (sleeps for 2 seconds), while the walker takes an entire 5 seconds to travel. We also initialize our CyclicBarrier to 4, which is the number of friends in the group:

    Thread walker = new Thread(getRunnable("walker", 5));
    Thread bus = new Thread(getRunnable("bus", 4));        
    Thread train = new Thread(getRunnable("train", 3));
    Thread plane = new Thread(getRunnable("plane", 2));
    barrier = new CyclicBarrier(4);

Waiting via the Barrier

Our friends need to travel to each location, but can’t proceed to the next city until the entire group arrives. Each thread will need to call await to ensure they don’t head off to the next city too soon:

    Thread.sleep(secs * 1000); //simulates time it takes to travel
    System.out.println("Thread " + type + " reached " + locations[i]);
    System.out.println("Thread " + type + " waiting for others...");
    barrier.await(); //blocks until others have arrived

The code also allows all of the friends to visit each city using the same object, showcasing the cyclic nature of the barrier.

The CyclicBarrier can be used in various applications for synchronizing work between threads. For more information, consult the Javadocs

Post navigation


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>