I was reading through the java.util.concurrent API, and found that
CountDownLatch
: A synchronization aid that allows one or more threads to wait until a set of operations being per开发者_运维百科formed in other threads completes.CyclicBarrier
: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
To me both seems equal, but I am sure there is much more to it.
For example, in CoundownLatch, the countdown value could not be reset, that can happen in the case of CyclicBarrier
.
Is there any other difference between the two?
What are theuse cases
where someone would want to reset the value of countdown?There's another difference.
When using a CyclicBarrier
, the assumption is that you specify the number of waiting threads that trigger the barrier. If you specify 5, you must have at least 5 threads to call await()
.
When using a CountDownLatch
, you specify the number of calls to countDown()
that will result in all waiting threads being released. This means that you can use a CountDownLatch
with only a single thread.
"Why would you do that?", you may say. Imagine that you are using a mysterious API coded by someone else that performs callbacks. You want one of your threads to wait until a certain callback has been called a number of times. You have no idea which threads the callback will be called on. In this case, a CountDownLatch
is perfect, whereas I can't think of any way to implement this using a CyclicBarrier
(actually, I can, but it involves timeouts... yuck!).
I just wish that CountDownLatch
could be reset!
One major difference is that CyclicBarrier takes an (optional) Runnable task which is run once the common barrier condition is met.
It also allows you to get the number of clients waiting at the barrier and the number required to trigger the barrier. Once triggered the barrier is reset and can be used again.
For simple use cases - services starting etc... a CountdownLatch is fine. A CyclicBarrier is useful for more complex co-ordination tasks. An example of such a thing would be parallel computation - where multiple subtasks are involved in the computation - kind of like MapReduce.
One point that nobody has yet mentioned is that, in a CyclicBarrier
, if a thread has a problem (timeout, interrupted...), all the others that have reached await()
get an exception. See Javadoc:
The CyclicBarrier uses an all-or-none breakage model for failed synchronization attempts: If a thread leaves a barrier point prematurely because of interruption, failure, or timeout, all other threads waiting at that barrier point will also leave abnormally via BrokenBarrierException (or InterruptedException if they too were interrupted at about the same time).
I think that the JavaDoc has explained the differences explicitly. Most people know that CountDownLatch can not be reset, however, CyclicBarrier can. But this is not the only difference, or the CyclicBarrier could be renamed to ResetbleCountDownLatch. We should tell the differences from the perspective of their goals, which are described in JavaDoc
CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
CyclicBarrier: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
In countDownLatch, there is one or more threads, that are waiting for a set of other threads to complete. In this situation, there are two types of threads, one type is waiting, another type is doing something, after finishes their tasks, they could be waiting or just terminated.
In CyclicBarrier, there are only one type of threads, they are waiting for each other, they are equal.
The main difference is documented right in the Javadocs for CountdownLatch. Namely:
A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.
source 1.6 Javadoc
A CountDownLatch is used for one-time synchronization. While using a CountDownLatch, any thread is allowed to call countDown() as many times as they like. Threads which called await() are blocked until the count reaches zero because of calls to countDown() by other unblocked threads. The javadoc for CountDownLatch states:
The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. ...
Another typical usage would be to divide a problem into N parts, describe each part with a Runnable that executes that portion and counts down on the latch, and queue all the Runnables to an Executor. When all sub-parts are complete, the coordinating thread will be able to pass through await. (When threads must repeatedly count down in this way, instead use a CyclicBarrier.)
In contrast, the cyclic barrier is used for multiple sychronization points, e.g. if a set of threads are running a loop/phased computation and need to synchronize before starting the next iteration/phase. As per the javadoc for CyclicBarrier:
The barrier is called cyclic because it can be re-used after the waiting threads are released.
Unlike the CountDownLatch, each call to await() belongs to some phase and can cause the thread to block until all parties belonging to that phase have invoked await(). There is no explicit countDown() operation supported by the CyclicBarrier.
This question has been adequately answered already, but I think I can value-add a little by posting some code.
To illustrate the behaviour of cyclic barrier, I have made some sample code. As soon as the barrier is tipped, it is automatically reset so that it can be used again (hence it is "cyclic"). When you run the program, observe that the print outs "Let's play" are triggered only after the barrier is tipped.
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierCycles {
static CyclicBarrier barrier;
public static void main(String[] args) throws InterruptedException {
barrier = new CyclicBarrier(3);
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
System.out.println("Barrier automatically resets.");
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
new Worker().start();
}
}
class Worker extends Thread {
@Override
public void run() {
try {
CyclicBarrierCycles.barrier.await();
System.out.println("Let's play.");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
When I was studying about Latches and cyclicbarriers I came up with this metaphors. cyclicbarriers: Imagine a company has a meeting room. In order to start the meeting, a certain number of meeting attendees have to come to meeting (to make it official). the following is the code of a normal meeting attendee (an employee)
class MeetingAtendee implements Runnable {
CyclicBarrier myMeetingQuorumBarrier;
public MeetingAtendee(CyclicBarrier myMileStoneBarrier) {
this.myMeetingQuorumBarrier = myMileStoneBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " i joined the meeting ...");
myMeetingQuorumBarrier.await();
System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("Meeting canceled! every body dance <by chic band!>");
}
}
}
employee joins the meeting, waits for others to come to start meeting. also he gets exited if the meeting gets canceled :) then we have THE BOSS how doses not like to wait for others to show up and if he looses his patient, he cancels meeting.
class MeetingAtendeeTheBoss implements Runnable {
CyclicBarrier myMeetingQuorumBarrier;
public MeetingAtendeeTheBoss(CyclicBarrier myMileStoneBarrier) {
this.myMeetingQuorumBarrier = myMileStoneBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "I am THE BOSS - i joined the meeting ...");
//boss dose not like to wait too much!! he/she waits for 2 seconds and we END the meeting
myMeetingQuorumBarrier.await(1,TimeUnit.SECONDS);
System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("what WHO canceled The meeting");
} catch (TimeoutException e) {
System.out.println("These employees waste my time!!");
}
}
}
On a normal day, employee come to meeting wait for other to show up and if some attendees don`t come they have to wait indefinitely! in some special meeting the boss comes and he does not like to wait.(5 persons need to start meeting but only boss comes and also an enthusiastic employee) so he cancels the meeting (angrily)
CyclicBarrier meetingAtendeeQuorum = new CyclicBarrier(5);
Thread atendeeThread = new Thread(new MeetingAtendee(meetingAtendeeQuorum));
Thread atendeeThreadBoss = new Thread(new MeetingAtendeeTheBoss(meetingAtendeeQuorum));
atendeeThread.start();
atendeeThreadBoss.start();
Output:
//Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// These employees waste my time!!
// Meeting canceled! every body dance <by chic band!>
There is another scenario in which another outsider thread (an earth quake) cancels the meeting (call reset method). in this case all the waiting threads get woken up by an exception.
class NaturalDisasters implements Runnable {
CyclicBarrier someStupidMeetingAtendeeQuorum;
public NaturalDisasters(CyclicBarrier someStupidMeetingAtendeeQuorum) {
this.someStupidMeetingAtendeeQuorum = someStupidMeetingAtendeeQuorum;
}
void earthQuakeHappening(){
System.out.println("earth quaking.....");
someStupidMeetingAtendeeQuorum.reset();
}
@Override
public void run() {
earthQuakeHappening();
}
}
running code will result in funny output:
// Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// earth quaking.....
// what WHO canceled The meeting
// Meeting canceled! every body dance <by chic band!>
You can also add a secretary to meeting room, if a meeting is held she will document every thing but she is not part of the meeting:
class MeetingSecretary implements Runnable {
@Override
public void run() {
System.out.println("preparing meeting documents");
System.out.println("taking notes ...");
}
}
Latches: if the angry boss wants to hold an exhibition for company customers, every thing needs to be ready (resources). we provide a to-do list every worker (Thread) dose his job and we check the to-do list (some workers do painting, others prepare sound system ...). when all the items in to-do list are complete (resources are provided) we can open the doors to customers.
public class Visitor implements Runnable{
CountDownLatch exhibitonDoorlatch = null;
public Visitor (CountDownLatch latch) {
exhibitonDoorlatch = latch;
}
public void run() {
try {
exhibitonDoorlatch .await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("customer visiting exebition");
}
}
And the workers how are preparing the exhibition:
class Worker implements Runnable {
CountDownLatch myTodoItem = null;
public Worker(CountDownLatch latch) {
this.myTodoItem = latch;
}
public void run() {
System.out.println("doing my part of job ...");
System.out.println("My work is done! remove it from todo list");
myTodoItem.countDown();
}
}
CountDownLatch preperationTodoList = new CountDownLatch(3);
// exhibition preparation workers
Worker electricalWorker = new Worker(preperationTodoList);
Worker paintingWorker = new Worker(preperationTodoList);
// Exhibition Visitors
ExhibitionVisitor exhibitionVisitorA = new ExhibitionVisitor(preperationTodoList);
ExhibitionVisitor exhibitionVisitorB = new ExhibitionVisitor(preperationTodoList);
ExhibitionVisitor exhibitionVisitorC = new ExhibitionVisitor(preperationTodoList);
new Thread(electricalWorker).start();
new Thread(paintingWorker).start();
new Thread(exhibitionVisitorA).start();
new Thread(exhibitionVisitorB).start();
new Thread(exhibitionVisitorC).start();
In a nutshell, just to understand key functional differences between the two :
public class CountDownLatch {
private Object mutex = new Object();
private int count;
public CountDownLatch(int count) {
this.count = count;
}
public void await() throws InterruptedException {
synchronized (mutex) {
while (count > 0) {
mutex.wait();
}
}
}
public void countDown() {
synchronized (mutex) {
if (--count == 0)
mutex.notifyAll();
}
}
}
and
public class CyclicBarrier {
private Object mutex = new Object();
private int count;
public CyclicBarrier(int count) {
this.count = count;
}
public void await() throws InterruptedException {
synchronized (mutex) {
count--;
while(count > 0)
mutex.wait();
mutex.notifyAll();
}
}
}
except, of course, features like non-blocking, timed waiting, diagnostics and everything which has been in details explained in the above answers.
The above classes are, however, fully functional and equivalent, within the provided functionality, to their correspondent namesakes.
On a different note, CountDownLatch
's inner class subclasses AQS
, while CyclicBarrier
uses ReentrantLock
(my suspicion is it could be other way around or both could use AQS or both use Lock -- without any loss of performance efficiency)
In CountDownLatch, threads waits for other threads to complete their execution. In CyclicBarrier, worker threads wait for each other to complete their execution.
You can not reuse same CountDownLatch instance once count reaches to zero and latch is open, on the other hand CyclicBarrier can be reused by resetting Barrier, Once barrier is broken.
One obvious difference is, only N threads can await on a CyclicBarrier of N to be release in one cycle. But unlimited number of threads can await on a CountDownLatch of N. The count down decrement can be done by one thread N times or N threads one time each or combinations.
In the case of CyclicBarrier, as soon as ALL child threads begins calling barrier.await(), the Runnable is executed in the Barrier. The barrier.await in each child thread will take different lengh of time to finish, and they all finish at the same time.
CountDownLatch is a count down of anything; CyclicBarrier is a count down for thread only
assume there are 5 worker threads and one shipper thread, and when workers produce 100 items, shipper will ship them out.
For CountDownLatch, the counter can be on workers or items
For CyclicBarrier, the counter can only on workers
If a worker falls infinite sleep, with CountDownLatch on items, Shipper can ship; However, with CyclicBarrier, Shipper can never be called
@Kevin Lee and @Jon I tried CyclicBarrier with Optional Runnable. Looks like it runs in the beginning and after the CyclicBarrier is tipped. Here is the code and output
static CyclicBarrier barrier;
public static void main(String[] args) throws InterruptedException {
barrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("I run in the beginning and after the CyclicBarrier is tipped");
}
});
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
System.out.println("Barrier automatically resets.");
new Worker().start();
Thread.sleep(1000);
new Worker().start();
Thread.sleep(1000);
new Worker().start();
}
Output
I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.
Barrier automatically resets.
I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.
精彩评论