23.5 Special-Purpose Synchronizers

The java.util.concurent package provides classes that implement useful special-purpose synchronization idioms that impose specific behavior on how threads can collectively make progress through some algorithm. We consider two such classes in this section: CyclicBarrier and CountDownLatch.

Cyclic Barrier

The java.util.concurrent.CyclicBarrier class implements a barrier upon which a set of threads have to synchronize before they are all allowed to proceed. The threads may need to wait for one another until all threads reach the barrier. When this happens the barrier will trip, allowing them to continue. The barrier is cyclic, as the same barrier can be reused after the waiting threads have been released.

The following constructors of the CyclicBarrier class can be used to create a barrier.

Click here to view code image

CyclicBarrier(int parties)
CyclicBarrier(int parties, Runnable barrierAction)

Both methods create a barrier that will trip when the specified number of parties (i.e., threads) are waiting for it—that is, when these invoke the await() method on it.

The barrier created by the second method will execute the given barrier action when the barrier is tripped. This action is performed by the last thread arriving at the barrier.

The declaration at (1) below creates a barrier that will trip when three threads synchronize on it. The declaration at (2) creates a barrier that will trip when five threads are waiting for it. In addition, a barrier action is defined that will be performed when the barrier is tripped. Typically, a barrier action can be used for consolidating any results computed by the threads thus far.

Click here to view code image

CyclicBarrier barrier1 = new CyclicBarrier(3);                     // (1)
CyclicBarrier barrier2 = new CyclicBarrier(5, () ->
         System.out.println(“All results accumulated.”));          // (2)

A cyclic barrier is shared by the threads wishing to synchronize on it. When a thread wants to wait at the barrier, it calls the await() method on the barrier. This defines a barrier point. The call blocks at the barrier point until the number of threads required to trip the barrier is reached—that is, the remaining threads also invoke the await() method. Otherwise, the barrier will not trip as long as the number of waiting threads is less than the number required by the barrier.

Click here to view code image

// Thread t1 waits on barrier1 at this barrier point.
barrier1.await();            // Can continue when the barrier is tripped.

// Thread t2 waits on barrier1 at this barrier point.
barrier1.await();            // Can continue when the barrier is tripped.

// Thread t3 waits on barrier1 at this barrier point.
barrier1.await();            // Can continue when the barrier is tripped.

The barrier barrier1 is tripped when any three threads invoke the await() method on this barrier—for example, threads t1, t2, and t3, as shown above. When tripped, the waiting threads can proceed, and the cyclic barrier resets itself and can be tripped again.

The CyclicBarrier class also defines methods to query and reset a barrier.

Click here to view code image

int await() throws InterruptedException, BrokenBarrierException
int await(long timeout, TimeUnit unit) throws InterruptedException,
                                              BrokenBarrierException,
                                              TimeoutException

Both methods wait until all parties have invoked the await() method on this barrier, or until the specified waiting time elapses, as in the second method.

These methods return the arrival index of the current thread, index N-1 for the first thread to arrive and 0 for the last thread to arrive, where N is the number of parties required to trip this barrier.

An InterruptedException is thrown if the current thread was interrupted while waiting.

A BrokenBarrierException is thrown if another thread was interrupted or timed out while the current thread was waiting, or the barrier was reset, or the barrier was broken when the await() method was called, or any barrier action failed due to an exception.

A TimeoutException is thrown if any specified timeout elapses. The barrier is then broken.

int getParties()

Returns the number of parties required to trip this barrier.

boolean isBroken()

Queries whether this barrier is in a broken state. A barrier can break due to an interruption, a timeout, the last reset, or a failed barrier action due to an exception. It returns true if any of the parties broke the barrier; otherwise, it returns false.

void reset()

Resets the barrier to its initial state—that is, the wait count of the barrier is set to 0. Any parties currently waiting at this barrier will return with a Broken-BarrierException.