Imagine a seminar which will start only when a certain number of attendees(say, 5) have arrived.
If asked, how would you achieve this in a java program.
The answer is by using a CyclicBarrier
.
What is a CyclicBarrier
CyclicBarrier
is a utility that is used to achieve thread synchronization in java.
When there are more than 1 threads, it allows the threads to wait for each other till all the threads reach a common point of execution.
This common point is called barrier point.
If there are 5 threads and 1 thread reaches the barrier point first, then it will wait till the other 4 also reach the same point.
Similarly, if 2 threads reach the barrier point, then they will wait till the other 3 also reach there.
Waiting threads can not move past the barrier point till all the threads reach there.
How CyclicBarrier Works
In order to use CyclicBarrier
, create an object of java.util.concurrent.CyclicBarrier
class. This class was added in java 1.5.
It takes an integer as argument which is the total number of threads that will wait for each other to reach the barrier point.
Example,
CyclicBarrier barrier = new CyclicBarrier(3);
CyclicBarrier
class has an await()
method. A thread when calls this method on an object of CyclicBarrier
goes into waiting state till all the threads given at the time of creation of CyclicBarrier
call await
.
Thus, for the above CyclicBarrier
, if a thread calls await()
, then its execution will halt till two other threads also call await()
. This way, all the threads will be at the same point.
Therefore, await()
method can be considered as a barrier point in CyclicBarrier
. When all the threads call await()
method, then barrier is said to be broken or crossed.
Javadoc of await()
method states
Waits until all parties have invoked
await()
on this barrier.
where parties means threads that are part of CyclicBarrier
.
Following are some important points regarding await
method
- All threads should call
await
on the sameCyclicBarrier
object. - If even one thread does not call
await
, then all the threads that have calledawait
will keep on waiting forever. - If there are 5 threads in a
CyclicBarrier
out of which 4 have calledawait
and are waiting for the 5th thread to callawait
.
But 5th thread callsreset
method inCyclicBarrier
object, then all the threads will terminate by throwing ajava.util.concurrent.BrokenBarrierException
. - There is an overloaded
await
method which takes an integer as a timeout. If a thread callsawait
, then it waits for the specified time for other threads to cross the barrier or callawait()
method else terminates with ajava.util.concurrent.TimeoutException
.
CyclicBarrier example
Below is a class that represents a task performed by a thread.
It implements java.lang.Runnable
interface and overrides its run()
method.
Learn how to override a method in java here.
Object of this class is supplied to different threads.
Worker.java
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; class Worker implements Runnable { CyclicBarrier barrier; /** * Constructor * @param b */ public Worker(CyclicBarrier b) { this.barrier = b; } @Override public void run() { try { System.out.println("Started: " + Thread.currentThread().getName()); // wait till all the threads reach this point barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } System.out.println("Finished: " + Thread.currentThread().getName()); } }
Note that the object of Worker has a CyclicBarrier
. Since the same Worker object is supplied to the threads, all threads will have access to same CyclicBarrier
object.
Below is the class which creates a CyclicBarrier
object with a count of 4.
This means that we are synchronizing 4 threads and if a thread calls await on this CyclicBarrier
object, then it will be stuck till other 3 threads also call await()
on the same CyclicBarrier
object.
It then creates an object of Worker class supplying it the CyclicBarrier
object and creates 3 threads with the Worker object. Finally it starts the three threads and itself calls await()
.
Learn how to create and start a thread here.
Now till all the other 3 threads call await()
, this thread will be stuck. As soon as the threads start, they call await()
and when all the four threads have called await()
, they continue execution past the call to await()
.
CyclicBarrierDemo.java
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args){ // create an object of cyclicbarrier with a thread count of 4 CyclicBarrier barrier = new CyclicBarrier(4); // create a task Task obj = new Task(barrier); // create three worker threads Thread t1 = new Thread(obj); Thread t2 = new Thread(obj); Thread t3 = new Thread(obj); // start threads t1.start(); t2.start(); t3.start(); try { System.out.println("Main: Waiting for the threads to call await"); // 4th thread to call await barrier.await(); Thread.sleep(2000); } catch (BrokenBarrierException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("All Threads completed!!!"); } }
Below output will clarify the flow of program
Main: Waiting for the threads to call await
Started: Thread-2
Started: Thread-1
Started: Thread-0
Finished: Thread-0
Finished: Thread-2
Finished: Thread-1
All Threads completed!!!
Order of thread execution might be different every time the program is executed.
CyclicBarrier: Version 2
java.util.concurrent.CyclicBarrier
has another constructor which takes a thread count and an object of java.lang.Runnable
as argument.
This second argument is the task which is executed when all the threads have crossed the barrier or have called await()
method.
This task will be executed by the last thread that crosses the barrier or calls await()
.
This task is an object of type java.lang.Runnable
and is also called Barrier Action.
Thus, a CyclicBarrier
can be used to perform a task when all threads have reached a common point or you can also say, it can be used to combine the result of all the threads after their execution.
Example,
Below code creates an object of CyclicBarrier
along with a task that will be executed when all the threads cross the barrier.
Rest of the program remains the same as written above.
// barrier with finish task CyclicBarrier barrier = new CyclicBarrier(4, new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " has crossed the barrier last"); } } ));
Output of this code put in the above program is
Waiting for the threads to call await
Started: Thread-3
Started: Thread-2
Started: Thread-1
Thread-3 has crossed the barrier last
Finished: Thread-3
Finished: Thread-1
Finished: Thread-2
All Threads completed!!!
Remember that the last thread will be different every time the program is executed.
BrokenBarrierException
A java.util.concurrent.BrokenBarrierException
is raised in the following cases
- If some threads are waiting after calling
await()
method and another thread callsreset()
method on the sameCyclicBarrier
object, all the waiting threads terminate by throwing this exception. - A thread has already called
reset()
method and another thread callsawait()
, this exception will be raised. - A thread has terminated with a
TimeoutException
after callingawait()
with a timeout, other threads which callawait()
afterwards raise this exception.
Remember that the CyclicBarrier
object should be the same in all the cases.
Where to use CyclicBarrier
- A
CyclicBarrier
can be used to break a large task into smaller sub-tasks where each task will be performed by a separate thread and the result of all the threads can be combined in the final task ofCyclicBarrier
or the Barrier Action.
Example, Summing up the rows of a matrix where each thread will sum up a single row and final sum will be calculated in Barrier Action. - Implementation of a multi player game where the game will start only when all the players have reached.
Hope this article helped you to understand the concept of CyclicBarrier
in java.