3 lutego 2013

Java synchronizers - Countdownlatch

Package java.concurrency contains many high level APIs for working with concurrency. It has been added to JDK in version 5. It's quite long time ago. However many developers still use raw Thread and synchronization. I'm pretty sure it is not because they like it but more likely they don't know what kind of goodies they have at their disposal. So in order to spread the word I would like to present Java synchronizers and how to work with them.

But what is so wrong with using Thread class and basic synchronization ? Well, actually nothing. It works fine. However in many cases it requires from a developer a lot of attention for details. Multithreading is hard issue and it gets even harder when you operate on low level API and need to take care of everything.

Because of that I want to present you three mechanisms that will help you write better and cleaner concurrent apps - CountDownLatch, CyclicBarrier and Semphore. In this post I'm describing CountDownLatch.

As we can read in documentation the CountDownLatch is "A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes". How it achieves that? Well, it is pretty simple. CountDownLatch object contains an internal counter and two very important methods:
  •  countDown - decreases value of an inner counter
  •  await - stops execution of a threat that invokes this method until an inner counter reaches zero

I think that after this short description you already discovered how and when use the CountDownLatch but to be sure let's see an example. Let's say we have something like this:

class MyTask implements Runnable {

 public MyTask(int i) {
  // assign vars and init state of object
 }

 @Override
 public void run() {

  // do some complicated stuff...
 }
}

public class Test {

 public static void main(String[] args) throws Exception {
  
  int noOfThreads = Integer.parseInt(args[0]);
  ExecutorService service = Executors
    .newFixedThreadPool(noOfThreads);
  
  for(int i = 0;i < noOfThreads;i++){
   
   service.execute(new MyTask(i));
  }
  // need to wait for tasks to finish
  
  // do some necessary stuff after tasks finished
 }
}
For sake of the example I have omitted checking if user passed correct args etc. I want to keep it simple. So what we have here is many tasks that need to be executed in parallel. We put them into the ExecutorService and in order to continue we need to wait for all of them to finish. But how we will do that ? Well, in my career I have seen many approaches. For instance:
service.shutdown();
while(service.isTerminated()){
}
It will work however such an approach will consume pointlessly your CPU and it is not very elegant. We can use wait-notify approach, we can create a counter and check it periodically. There are many solutions. However I think the best possible solution is to use the CountDownLatch. The problem that we are considering is a perfect case of use for this class.
class MyTask implements Runnable {

 private CountDownLatch latch;
 
 public MyTask(int i, CountDownLatch latch){

  this.latch = latch;
  // assign vars and init state of object
 }
 
 @Override
 public void run() {
  
  try {
   // do some complicated stuff...
  } finally {
   latch.countDown();
  }
 }
}

public class Test {

 public static void main(String[] args) throws Exception {
  
  int noOfThreads = Integer.parseInt(args[0]);
  CountDownLatch latch = new CountDownLatch(noOfThreads);
  ExecutorService service = Executors
    .newFixedThreadPool(noOfThreads);
  
  for(int i = 0;i < noOfThreads;i++){
   
   service.execute(new MyTask(i, latch));
  }
  
  latch.await();
  // do some necessary stuff after tasks finished
 }
}}
So now what we have is the CountDownLatch with number of threads that need to finish before main thread can go further. We pass the CountDownLatch to tasks constructor and each task calls countDown method when it is finished. countDown method decreases the inner CountDownLatch counter value. Method await stops the main thread until CountDownLatch object counter reaches zero. So as you can see we have clear and easy to read solution.

Well, it's pretty much it! I know I didn't touch issues like what will happen when we call countDown method too many times etc. Yeah, I know it. But all I wanted was to arouse your interest, not to copy Java documentation.

I will write two more posts under "Java synchronizers" series. One about the Semaphore class and the other one about the CyclicBarrier. So see you soon!

Brak komentarzy:

Prześlij komentarz