One example is given by one of our trainers when he was explaining difference between CountDownLatch and CyclicBarrier.
CountDownLatch: Suppose a stone can be lifted by
A CyclicBarrier
is reusable, so it's more like a racing tour where everyone meets at a waypoint before proceeding on the next leg of the tour.
For the CyclicBarrier, One real time example that I could think of; Lets imagine there is a group of tourists on a tempo traveller. There are multiple places that are to be visited in a day. The tempo driver knows there are x number of tourists. Once the first location is reached, all the tourists go out and return back at different points of time; however the tempo and the travellers have to wait until all tourists return back. Once all of them return the driver proceeds to the next location and the same process repeats. Here, the CyclicBarrier is initialized with the number of tourists. Each tourist is like a Thread and upon returning back, they call CyclicBarrier await() so that they wait until all other tourists are back. Let me now what you think
Real World Example I can see that all the answers are actually missing a real example. As in how these classes can be used in a software realm
CountDownLatch A Multithreaded download manager. The download manager will start multiple threads to download each part of the file simultaneously.(Provided the server supports multiple threads to download). Here each thread will call a countdown method of an instantiated latch. After all the threads have finished execution, the thread associated with the countdown latch will integrate the parts found in the different pieces together into one file
CyclicBarrier Same scenario as above..But assume the files are downloaded from P2P. Again multiple threads downloading the pieces. But here, suppose that you want the intergity check for the downloaded pieces to be done after a particular time interval. Here cyclic barrier plays an important role. After each time interval, each thread will wait at the barrier so that thread associated with cyclibarrier can do the integrity check. This integrity check can be done multiple times thanks to CyclicBarrier
Please correct me if anything not proper.
CountDownLatch: "The Best Real Life Example is - Race"
(Any Type of Race for Example: Horse Race or Bike Race or Car Race etc.,)
The Horse Race is also one of the Best Real Life Example can implement using CountDownLatch
.
We use Two CountDownLatch
for Start and finish the Race.
CountDownLatch start = new CountDownLatch(1); // Start signal - will be always 1 only once All Horses Reach at Starting Point signal for START RACE.
CountDownLatch finish = new CountDownLatch(horses_Count); // Number of horses participating in Race nothing but Threads/Horses Count.
Horses - is nothing but Threads.
start.await() :
Each Horse/Thread once Reach at starting gate/starting point it will wait for other horses/Threads to reach at starting gate/starting point is nothing but - start.await();
start.countDown() : Once all horses/Threads reached at starting gate/starting point we signal to start Race is nothing but - start.countDown();
When start.countDown();
is called it will notifyAll()
to All waiting Horses/Threads to Start Race.
finish.await() : Once all horses/Threads started Race the Main Thread will be wait to finish or complete by All horses/Threads is nothing but - finish.await();
finish.countDown(): Once each horse/Thread finish Race It will be reduce the count once last horse/Thread reduce count to ZERO then Race Completed/Finished finish.countDown();
When finish.countDown();
is called when count became to ZERO it will notify()
to waiting Main Thread - All Horses/Threads Finished/Completed the RACE.
In a hypothetical theater:
Here, a person is a thread, a play is a resource.
Here are my observations : -----> 1. Where to use what : In a Cyclic barrier threads have to wait for other threads to give some output, and then all threads have to resume processing. So after completing its execution, each thread calls await() method and waits. When the barrier detects that all the threads have reached it, it notifies all its waiting threads and they can resume further execution. Barrier keeps track of count.
In a CountDownLatch single main thread waits for all threads to complete. Each thread reduces the count by 1 after completing execution. After the count reaches 0, the main thread can resume further execution. Main thread keeps track of count.
Phaser : In both ways, count of threads should be known beforehand. It is not possible to add/remove threads dynamically. If the count is not reached, thread keeping track of count will wait infinitely. With the Phaser, the number of threads can be dynamic and vary with time. It is similar to Cyclic Barrier. Thread registers with a barrier. After completing execution, it has two options. It can signal that it has arrived at the barrier point and without waiting for others it can deregister from the Phaser. Second option is that it can wait for the other registered Threads to arrive at the barrier point.
Counts : While creating a CyclicBarrier the no of worker threads includes main thread if it is also going to wait for other threads to complete. While creating a CountDownLatch just needs to mention how many worker threads main thread will to wait to complete. In CountDownLatch there is the concept of main and worker threads and the main waiting thread is not included in count while creating a latch. Phaser can return the current count of registered Threads.
Intent of await() : In CyclicBarrier :: await() all threads including main thread are equal and wait for each other. Hence await() should be given in all threads(worker as well as main thread). CountDownLatch :: await() is given in main thread only and it makes main thread wait till other worker threads make count to 0. Thus internal implementation of both await() is different. There are two concepts in Phaser :: arrival to the barrier(arrive() and arriveAndDeregister()) and waiting(awaitAdvance(phase_number)) for other threads.
Parties and Waiting threads : CountDownLatch cannot give number of waiting threads but can give parties(cl.getCount()), CyclicBarrier can give no of waiting threads cb.getNumberWaiting(), and parties(cb.getParties())
Work responsibilities : Worker thread in countdownlatch need to do countdown(), and await() is done by one single main thread. In cyclicBarrier worker and main threads all do only await() on each other.
Reuse : CyclicBarrier can be reused. cb.await() works for new threads say t1, t2 and main. And second call to cb.await() for new threads t3,t4 and main also works. Main will wait in both calls, that is system is automatically internally resetting the count(or reset()) after barrier is exitted. CountDownLatch cannot be reused. - cl.await() works for new threads say t1, t2 and main. Main thread waits for t1, t2 to complete. But for second cl.await() call for new threads t3,t4 and main will not wait. Phaser object can be re-used again once all the Threads in the set have crossed the barrier point.
After Finish Events : While creating, no finish event can be given in CountDownLatch but it can be given in CyclicBarrier.
class MyClass {
static class MyThread implements Runnable
{
long waitTime;
CyclicBarrier cyclicBarrier;
CountDownLatch countdownlatch;
Phaser phaser;
MyThread( long waitTime, CyclicBarrier cyclicBarrier, CountDownLatch countdownlatch, Phaser phaser){
this.waitTime = waitTime;
this.cyclicBarrier = cyclicBarrier;
this.countdownlatch = countdownlatch;
this.phaser = phaser;
this.phaser.register(); //Note additional step here
}
@Override
public void run() {
try {
Thread.sleep(waitTime);
// Diff 4 -----> countdownlatch worker threads need to do countdown and await is done by one single main thread
//, cyclicBarrier worker threads await on each other
countdownlatch.countDown();
cyclicBarrier.await();
phaser.arriveAndAwaitAdvance();
System.out.println("cyclicBarrier :: " +
", name :: " + Thread.currentThread().getName()
+ ", parties :: " + cyclicBarrier.getParties()
+ ", waiting :: "+ cyclicBarrier.getNumberWaiting());
System.out.println("countdownlatch :: " +
"name :: " + Thread.currentThread().getName() +
", parties :: "+countdownlatch.getCount() +
", waiting :: " + "No method!!" );
System.out.println("phaser :: " +
"name :: " + Thread.currentThread().getName() +
", parties :: "+phaser.getRegisteredParties() +
", phase :: " + phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println("phaser :: " +
"name :: " + Thread.currentThread().getName() +
", parties :: "+phaser.getRegisteredParties() +
", phase :: " + phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println("phaser :: " +
"name :: " + Thread.currentThread().getName() +
", parties :: "+phaser.getRegisteredParties() +
", phase :: " + phaser.getPhase());
phaser.arriveAndDeregister();
if (phaser.isTerminated()) {
System.out.println("Phaser is terminated");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static class MyCBFinishEvent implements Runnable{
public void run() {
System.out.println("All threads have reached common barrier point "
+ ", CyclicBarrrierFinishEvent has been triggered");
System.out.println("You can update shared variables if any");
}
}
public static void main(String [] args) throws InterruptedException, BrokenBarrierException{
//Diff 1 ----- > No finish event can be given in CountDownLatch
//Diff 5 ------> CyclicBarrier no of worker threads includes main thread,
//CountDownLatch is just how many threads, the main waiting thread is not included in count.
CyclicBarrier cb = new CyclicBarrier(3, new MyCBFinishEvent());
CountDownLatch cl = new CountDownLatch(2);
Phaser ph = new Phaser();
//Diff 2 ----> CountDownLatch cant give num of waiting threads, CyclicBarrier can getNumberWaiting threads
System.out.println("Start CyclicBarrier - parties :: "+cb.getParties() + ", waiting :: " + cb.getNumberWaiting());
System.out.println("Start CountDownLatch - parties :: "+cl.getCount() + ", waiting :: " + "No method!!" );
Runnable t1 = new Thread(new MyThread( 10000, cb, cl, ph));
Runnable t2 = new Thread(new MyThread( 5000, cb, cl,ph));
Thread tt1 = new Thread(t1, "t1");
Thread tt2 = new Thread(t2, "t2");
tt1.start();
tt2.start();
//Diff 6 ---- > await meaning Main waits for t1 and t2 to complete,
//CyclicBarrier all are equal. each thread including main thread, if it wants to wait has to do await.
//CountDownLatch concept of waiting and workers. main thread await waits till other worker threads make count to 0.
cb.await();
cl.await();
System.out.println("End CyclicBarrier call 1 - parties :: "+cb.getParties() + ", waiting :: " + cb.getNumberWaiting());
System.out.println("End CountDownLatch call 1 - parties :: "+cl.getCount() + ", waiting :: " + "No method!!" );
System.out.println("main start created t3, t4 - parties :: "+cl.getCount() + ", waiting :: " + "No method!!" );
Runnable t3 = new Thread(new MyThread( 6000, cb, cl,ph));
Runnable t4 = new Thread(new MyThread( 100, cb, cl,ph));
Thread tt3 = new Thread(t3, "t3");
Thread tt4 = new Thread(t4, "t4");
tt3.start();
tt4.start();
//Diff -3 ----->
//CyclicBarrier - can be reused, main thread waited for t3, t4 to complete.
//CountDownLatch - for first cl.await(), main waited... second cl.await() call main did not wait!!!
cb.await();
cl.await();
System.out.println("End main - parties :: "+cb.getParties() + ", waiting :: " + cb.getNumberWaiting());
System.out.println("end main parties :: "+cl.getCount() + ", waiting :: " + "No method!!" );
}
}