April 01, 2016

Difference between CountDownLatch & CyclicBarrier in Java

The main difference between CountDownLatch & CyclicBarrier is that you can not re-use CountDownLatch once count reaches to zero, but you can reuse same CyclicBarrier even after barrier is broken. Let's first understand what exactly CountDownLatch & CyclicBarrier does..

CountDownLatch is a kind of synchronizer which allows one Thread to wait for one or more Threads before starts processing. This is very crucial requirement and often needed in server side core Java application and having this functionality built-in as CountDownLatch greatly simplifies the development.

CountDownLatch is introduced on Java 5 along with other concurrent utilities like CyclicBarrier, Semaphore, ConcurrentHashMap and BlockingQueue in java.util.concurrent package.

We can also implement same functionality using wait and notify mechanism in Java, but it requires lot of code and getting it write in first attempt is tricky, With CountDownLatch it can  be done in just few lines. It also allows flexibility on number of thread for which main thread should wait and it can wait for one thread or n number of thread, there is not much change on code.

Points to remember:
* Use CountDownLatch when one of Thread like main thread, require to wait for one or more thread to complete, before its start doing processing.
* You can not reuse CountDownLatch once count is reaches to zero, this is the main difference between CountDownLatch and CyclicBarrier,
* Main Thread wait on Latch by calling CountDownLatch.await() method while other thread calls CountDownLatch.countDown() to inform that they have completed.

Example:
1). Create a thread class Service, which implements Runnable:

package com.test.thread;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Service implements Runnable{
    private final String serviceName;
    private final int timeToStart;
    private final CountDownLatch latch;
 
    public Service(String serviceName, int timeToStart, CountDownLatch latch){
        this.serviceName = serviceName;
        this.timeToStart = timeToStart;
        this.latch = latch;
    }
 
    @Override
    public void run() {
        try {
            Thread.sleep(timeToStart);
        } catch (InterruptedException ex) {
            Logger.getLogger(Service.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println( serviceName + " is now UP");
        latch.countDown(); //reduce count of CountDownLatch by 1
    } 
}

2).  Create another class with Main method:

package com.test.thread;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
    public static void main(String args[]) {
       //count is 4 since we have 4 Threads (Services)  
       final CountDownLatch latch = new CountDownLatch(4);
       Thread service1 = new Thread(new Service("service1", 1000, latch));
       Thread service2 = new Thread(new Service("service2", 1000, latch));
       Thread service3 = new Thread(new Service("service3", 1000, latch));
       Thread service4 = new Thread(new Service("service4", 1000, latch));
       service1.start();
       service2.start();
       service3.start();
       service4.start();
       /*
       If we have a requirement that an Application should not start processing any thread until all service is up
       & ready to do there job. We can use CountdownLatch, in this example the main thread will start with count 4
       and wait until count reaches zero. Each thread once up and read will do a count down.
       This will ensure that main thread is not started processing until all services is up.
       */        
       try{
            latch.await();  //main thread is waiting on CountDownLatch to finish
            System.out.println("All services are up..Application is starting now!!");
       }catch(InterruptedException ie){
           ie.printStackTrace();
       }     
    } 
}

3).  When you run CountDownLatchDemo, you will get below output:
service2 is now UP
service3 is now UP
service1 is now UP
service4 is now UP
All services are up..Application is starting now!!


CyclicBarrier can perform a completion task once all thread reaches to the 'barrier'. It is a synchronizer introduced in JDK 5 on java.util.Concurrent package along with other concurrent utility like Counting Semaphore, BlockingQueue, ConcurrentHashMap etc. CyclicBarrier is similar to CountDownLatch and allows multiple threads to wait for each other (barrier) before proceeding.

CyclicBarrier also does the same thing but there is different you cannot reuse CountDownLatch once the count reaches zero while you can reuse CyclicBarrier by calling reset() method which resets Barrier to its initial State. What it implies that CountDownLatch is a good for one-time events like application start-up time and CyclicBarrier can be used to in case of the recurrent event.

When to use CyclicBarrier in Java, e.g.
1). To count population of India you can have 4 threads which count population from North, South, East, and West and once complete they can wait for each other, When last thread completed their task, Main thread or any other thread can add result from each zone and print total population.
2). To implement multi player game which cannot begin until all player has joined.

Points to remember:
1). If CyclicBarrier is initialized with 3 parties means 3 thread needs to call await method to break the barrier.
2). The thread will block on await() until all parties reach to the barrier, another thread interrupt or await timed out.
3). If another thread interrupts the thread which is waiting on barrier it will throw BrokernBarrierException as shown below:
java.util.concurrent.BrokenBarrierException
        at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:172)
        at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:327)
4). CyclicBarrier.reset() put Barrier on its initial state, other thread which is waiting or not yet reached barrier will terminate with java.util.concurrent.BrokenBarrierException.

Example:
1). Create a class which extends Thread
package com.test.thread;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Party extends Thread {
    private int duration;
    private CyclicBarrier barrier;

    public Party(int duration, CyclicBarrier barrier, String name) {
        super(name);
        this.duration = duration;
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(duration);
            System.out.println(Thread.currentThread().getName() + " is calling await()");
            barrier.await();
            System.out.println(Thread.currentThread().getName() + " has started running again");
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}




2).
package com.test.thread;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String args[]) throws InterruptedException, BrokenBarrierException {
        CyclicBarrier barrier = new CyclicBarrier(4);
        Party first = new Party(1000, barrier, "Party1");
        Party second = new Party(2000, barrier, "Party2");
        Party third = new Party(3000, barrier, "Party3");
        Party fourth = new Party(4000, barrier, "Party4");

        first.start();
        second.start();
        third.start();
        fourth.start();
        System.out.println(Thread.currentThread().getName() + " has finished");
    }
}

3). Run CyclicBarrierDemo, output will be:
main has finished
Party1 is calling await()
Party2 is calling await()
Party3 is calling await()
Party4 is calling await()
Party4 has started running again
Party3 has started running again
Party2 has started running again
Party1 has started running again

-K Himaanshu Shuklaa..

No comments:

Post a Comment

RSSChomp Blog Directory