Tuesday, July 19, 2011

CyclicBarrier, CountdownLatch and Semaphore

In this post I'd like to focus on CyclicBarrier, CountdownLatch and Semaphore – some of the classes for synchronization purposes from java.util.concurrent package. You can find here short descriptions, simple examples and illustrations of how these classes work. In the references section you can find links to the Java API docs and to the similar posts and articles.

So let's start from CyclicBarrier.

CyclicBarrier
Allows N-1 treads to wait on await() method until N-th thread calls await() method and then they resume their execution.
As this illustration shows there is a barrier for 3 parties. When T1 and T2 come they wait. When T3 comes an optional TA handler is called and (after it completes?) T1,2,3 resume their work. You can reuse CyclicBarrier many times by calling reset() method.

And the code example:

final CyclicBarrier cb = new CyclicBarrier(N);
for (int i = 0; i < N; i++) {
    final int idx = i;
    new Thread(new Runnable() {
        public void run() {
            System.out.println("T" + idx + ": await");
            try {
                cb.await();
            } catch (InterruptedException ex) {
                System.out.println("T" + idx + ": interrupted");
                return;
            } catch (BrokenBarrierException ex) {
                System.out.println("T" + idx + ": broken");
                return;
            }
            System.out.println("T" + idx + ": continue");
        }
    }).start();
}

Console output:
T0: await
T1: await
T2: await
T2: continue
T1: continue
T0: continue
Lines can "jump" a little bit because threads in these examples print out information to console concurrently. So you may have slightly different results.

CountdownLatch
Works like a counter – allows one or more threads to wait on await() method for another N threads to call countDown() method N times (total number of calls should be N).

As the illustration shows only TA is awaiting. T1,2,3 call countDown() and proceed their execution. When T3 calls countDown(), TA gets unlocked and can resume its work.

“HelloWorld app” for CountdownLatch:

final CountDownLatch cdl = new CountDownLatch(N);
        new Thread(new Runnable() {
            public void run() {
                System.out.println("awaiting...");
                try {
                    cdl.await();
                } catch (InterruptedException ex) {
                    System.out.println("await has been iterrupted");                
                    return;
                }
                System.out.println("ready");                
            }
        }).start();
        
        for (int i = 0; i < N; i++) {
            final int idx = i;
            new Thread(new Runnable() {
                public void run() {
                    System.out.println("T" + idx + ":countDown");
                    cdl.countDown();
                    System.out.println("T" + idx + ":continue");                
                }
            }).start();
        }

Console output:
awaiting...
T1:countDown
T0:countDown
T0:continue
T1:continue
T2:countDown
T2:continue
ready
It is different from CyclicBarrier:
1) it cannot be reused, used only one time
2) it does not block these N threads when they call countDown() method. Only thread on await() method waits.

Semaphore
Maintains N permits which is shared between M threads. Each thread can acquire or release permits. If there are not enough permits thread blocks until other threads release necessary amount of permits.

Let's see what is happening on the illustration above. There are 2 permits and 4 threads. Each thread acquires/releases only 1 permit. T1 and T2 do this and proceed their execution without being blocked. T3 and T4 block and wait for permits because there are no any permits available. T2 releases one permit and T4 proceeds its calculations (T3 is also might be chosen?). Next T4 releases its permit and T3 resumes. An finally T1 and T3 release their permits.

Simple example:

public static void main(String args[]) {
    final Semaphore sem = new Semaphore(N);
    acquire("T1", sem);
    acquire("T2", sem);
        
    release("Ta", sem);
    release("Tb", sem);
}
    
private static void acquire(final String id, final Semaphore s){
    new Thread(new Runnable() {
        public void run() {
            System.out.println(id + ": acquire");
            try {
                s.acquire();
            } catch (InterruptedException ex) {
                System.out.println(id + ": acquire|interrupted");
                return;
            }
            System.out.println(id + ": acquire|ready");
        }
    }).start();
}

private static void release(final String id, final Semaphore s){
    new Thread(new Runnable() {
        public void run() {
            System.out.println(id + ": release");
            s.release();
            System.out.println(id + ": release|ready");
        }
    }).start();
}

Console output:
T2: acquire
T2: acquire|ready
Tb: release
T1: acquire
Ta: release
Ta: release|ready
Tb: release|ready
T1: acquire|ready
Conclusion
As you can see this article shows very simple examples, for more advanced ones and for more information please read Java API docs. You can find links for further reading in the references section below.

References
  1. http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html – Java API docs for java.util.concurrent package;
  2. http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html – Java API docs for CountDownLatch;
  3. http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CyclicBarrier.html – Java API docs for CyclicBarrier;
  4. http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Semaphore.html – Java API docs for Semaphore;
  5. http://stackoverflow.com/questions/184147/countdownlatch-vs-semaphore - CountDownLatch vs. Semaphore on Stackoverflow.com;
  6. http://stackoverflow.com/questions/4168772/java-concurrency-countdown-latch-vs-cyclic-barrier - Java concurrency : Countdown latch vs Cyclic Barrier on Stackoverflow.com.

No comments:

Post a Comment