How to use CyclicBarrier

Sometimes we need to run several threads at once, make them start at the same time. The Java API provides us a class, CyclicBarrier, to accomplish this.

The Race Example

Let’s assume you have to create a silly program that simulates a car race. The semaphore (our CyclicBarrier) waits for all drivers to be ready to go green, then every driver drives until they get to the finish line.

First of all, the Driver class. It will have two variables: the driver’s name and his best lap time.

class Driver {
	
    private String name;
    private Double bestTime;

    public Driver(String name, Double bestTime) {
        this.name = name;
        this.bestTime = bestTime;
    }

    //getters & setters...
}

Next we’ll create a drive method. It represents the driver driving and it will last the time the driver takes to complete a lap. Finally, if the lap time is better than his best time, the bestTime variable is updated.

public void drive() throws InterruptedException {
    System.out.println(name + " starts running!!");
    Double lapTime = getLapTime();
    Thread.sleep(Math.round(lapTime*1000));
    System.out.println(name + " finished in " + lapTime + " seconds.");
    if (lapTime < bestTime) {
        System.out.println(name + " has beaten his best time!!");
        bestTime = lapTime;
    }
}

As you can see, we need to implement the getLapTime() method. As drivers aren’t machines, they don’t perform the same time every lap, so it will return a random number around their best time. The gap is 1 second, they can beat their best time up to 1 second or take a worse time up to 1 second too.

    private Double getLapTime() {
        Random r = new Random();
        return bestTime + r.nextDouble()*2 - 1;
    }

Driver class is ready. Now we want to use each driver in a different thread so they race at the same time. We’ll create three drivers, use them on three threads, and we’ll use CyclicBarrier to make them wait until every driver is ready.

In this example, their best performance are around 13 seconds (it’s a short circuit). Every driver arrives to the grid 2.5 seconds later than the last one, so the semaphore won’t go green until the last driver arrives, 5 seconds later than the first one.

String[] names =  {"Ayrton", "Michael", "Niki"};
Double[] bestTimes = {13.21, 13.03, 13.25};

final CyclicBarrier semaphore = new CyclicBarrier(3);

for (int i=0; i<3; i++) {
    final Driver driver = new Driver(names[i], bestTimes[i]);
    Thread t = new Thread() {
        public void run() {
            System.out.println(driver.getName() + " is ready.");
            try {
                semaphore.await();
                driver.drive();
            } catch (InterruptedException | BrokenBarrierException e) {
            }
        }
    };
    t.start();
    Thread.sleep(2500);
}

When we create the CyclicBarrier, our semaphore, we pass to the constructor the number of threads it’ll wait until it starts them all. Then we create a thread that will be suspended. The key is the semaphore.wait(), every following line of code won’t be executed until the CyclicBarrier starts the thread.

To get in the pool of the CyclicBarrier, we have to start the thread as usually. Finally we make the main thread sleep for 2.5 seconds before creating the next driver.

After running this program we’ll get something like this:

Ayrton is ready.
Michael is ready.
Niki is ready.
Ayrton starts running!!
Michael starts running!!
Niki starts running!!
Niki finished in 12.790270035868033 seconds.
Niki has beaten his best time!!
Ayrton finished in 13.484038866959247 seconds.
Michael finished in 13.909761762654298 seconds.

The first three lines will take 5 seconds to get printed, with a 2.5 seconds gap between them. But as soon as Niki is ready, we’ll get the following 3 lines, the racing start. This happens even though the main thread is suspended for another 2.5 seconds. They’re running on their own threads.

Despite of being the last one to arrive to the grid before the race, Niki wins the race after 12.79 seconds!

You can get the complete sourcecode on my GitHub project.

Leave a Reply

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