The Java concurrency API provides a class that allows one or more threads to wait until a set of operations are made. It's the CountDownLatch class. This class is initialized with an integer number, which is the number of operations the threads are going to wait for. When a thread wants to wait for the execution of these operations, it uses the await() method.
This method puts the thread to sleep until the operations are completed. When one of these operations finishes, it uses the countDown() method to decrement the internal counter
of the CountDownLatch class. When the counter arrives to 0, the class wakes up all the threads that were sleeping in the await() method.
In this recipe, you will learn how to use the CountDownLatch class implementing a video-conference system. The video-video-conference system will wait for the arrival of all the participants before it begins.
Getting ready
The example of this recipe has been implemented using the Eclipse IDE. If you use Eclipse or other IDE such as NetBeans, open it and create a new Java project.
How to do it...
Follow these steps to implement the example:
1. Create a class named Videoconference and specify that it implements the Runnable interface. This class will implement the video-conference system.
public class Videoconference implements Runnable{
2. Declare a CountDownLatch object named controller. private final CountDownLatch controller;
3. Implement the constructor of the class that initializes the CountDownLatch attribute. The Videoconference class will wait for the arrival of the number of participants received as a parameter.
public Videoconference(int number) { controller=new CountDownLatch(number);
}
4. Implement the arrive() method. This method will be called each time a participant arrives to the video conference. It receives a String type named name as the parameter.
public void arrive(String name){
5. First, it writes a message with the parameter it has received.
System.out.printf("%s has arrived.",name);
6. Then, it calls the countDown() method of the CountDownLatch object.
controller.countDown();
7. Finally, it writes another message with the number of participants, whose arrival is pending using the getCount() method of the CountDownLatch object.
System.out.printf("VideoConference: Waiting for %d participants.\n",controller.getCount());
8. Implement the main method of the video-conference system. It's the run() method that every Runnable object must have.
@Override
public void run() {
9. First, use the getCount() method to write a message with the number of participants in the video conference.
System.out.printf("VideoConference: Initialization: %d participants.\n",controller.getCount());
10. Then, use the await() method to wait for all the participants. As this method can throw an InterruptedException exception, you must include the code to process it.
try {
controller.await();
11. Finally, write a message to indicate that all the participants have arrived.
System.out.printf("VideoConference: All the participants have come\n");
System.out.printf("VideoConference: Let's start...\n");
} catch (InterruptedException e) { e.printStackTrace();
}
12. Create the Participant class and specify that it implements the Runnable interface. This class represents each participant in the video conference.
public class Participant implements Runnable {
13. Declare a private Videoconference attribute named conference. private Videoconference conference;
14. Declare a private String attribute named name. private String name;
15. Implement the constructor of the class that initializes both attributes.
public Participant(Videoconference conference, String name) { this.conference=conference;
this.name=name;
}
16. Implement the run() method of the participants.
@Override
public void run() {
17. First, put the thread to sleep for a random period of time.
long duration=(long)(Math.random()*10);
try {
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) { e.printStackTrace();
}
18. Then, use the arrive() method of the Videoconference object to indicate the arrival of this participant.
conference.arrive(name);
19. Finally, implement the main class of the example by creating a class named Main and add the main() method to it.
public class Main {
public static void main(String[] args) {
20. Create a Videoconference object named conference that waits for 10 participants.
Videoconference conference=new Videoconference(10);
21. Create Thread to run this Videoconference object and start it.
Thread threadConference=new Thread(conference);
threadConference.start();
22. Create 10 Participant objects, a Thread object to run each of them, and start all the threads.
for (int i=0; i<10; i++){
Participant p=new Participant(conference, "Participant "+i);
Thread t=new Thread(p);
t.start();
}
How it works...
The CountDownLatch class has three basic elements:
f The initialization value that determines how many events the CountDownLatch class waits for
f The await() method, called by the threads that wait for the finalization of all the events
f The countDown() method, called by the events when they finish their execution When you create a CountDownLatch object, the object uses the constructor's parameter to initialize an internal counter. Every time a thread calls the countDown() method, the CountDownLatch object decrements the internal counter in one unit. When the internal counter arrives to 0, the CountDownLatch object wakes up all the threads that were waiting in the await() method.
There's no way to re-initialize the internal counter of the CountDownLatch object or to modify its value. Once the counter is initialized, the only method you can use to modify its value is the countDown() method explained earlier. When the counter arrives to 0, all the calls to the await() method return immediately and all subsequent calls to the countDown() method have no effect.
There are some differences with respect to other synchronization methods, which are as follows:
f The CountDownLatch mechanism is not used to protect a shared resource or a critical section. It is used to synchronize one or more threads with the execution of various tasks.
f It only admits one use. As we explained earlier, once the counter of CountDownLatch arrives at 0, all the calls to its methods have no effect.
You have to create a new object if you want to do the same synchronization again.
The following screenshot shows the output of an execution of the example:
You can see how the last participants arrive and, once the internal counter arrives to 0, the CountDownLatch object wakes up the Videoconference object that writes the messages indicating that the video conference should start.
There's more...
The CountDownLatch class has another version of the await() method, which is given as follows:
f await(longtime,TimeUnitunit): The thread will be sleeping until it's
interrupted; the internal counter of CountDownLatch arrives to 0 or specified time passes. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS.