CountDownLatch and Semaphore

In Java’s concurrent programming, CountDownLatch and Semaphore are synchronization aids from the java.util.concurrent package. Both are used to control thread execution, but they serve different purposes and have different mechanisms.

CountDownLatch

A CountDownLatch is used to block a thread (or threads) until a set of operations being performed by other threads completes.

It is typically used when:

  • You want one thread to wait for multiple threads to finish.

  • You need a fixed number of signals before proceeding.

How It Works
  • Constructed with a count.
  • countDown() method decrements the count.
  • await() blocks the thread until the count reaches zero.
Constructors:
public CountDownLatch(int count)

Parameter: count – the number of times countDown() must be invoked before threads can pass through await().
Throws: IllegalArgumentException if count is negative.Code language: JavaScript (javascript)
  • Methods
Method Description
void await() Causes the current thread to wait until the latch has counted down to zero.
boolean await(long timeout, TimeUnit unit) Causes the current thread to wait until the latch has counted down to zero, or the specified timeout occurs.
void countDown() Decrements the count of the latch. When count reaches zero, all waiting threads are released.
long getCount() Returns the current count.
Program

This program demonstrates the use of a CountDownLatch in Java, which is a synchronization aid that allows one or more threads to wait until a set of operations being performed by other threads completes.

//CountDownLatchDemo.java
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
    static class Worker implements Runnable {
        private final CountDownLatch latch;
        Worker(CountDownLatch latch) {
            this.latch = latch;
        }
        @Override
        public void run() {
            // Simulate some work
            try {
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println(Thread.currentThread().getName() + " has completed its task");
                latch.countDown(); // Signal completion
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
	public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3); // Initialize with count 3
        // Create threads
        Thread[] threads = new Thread[3];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new Worker(latch));
            threads[i].start();
        }
        // Main thread waits for all threads to complete
        latch.await();
        System.out.println("All workers have completed their tasks");
    }
}

/*

C:\>javac CountDownLatchDemo.java

C:\>java CountDownLatchDemo
Thread-0 has completed its task
Thread-2 has completed its task
Thread-1 has completed its task
All workers have completed their tasks

C:\>java CountDownLatchDemo
Thread-2 has completed its task
Thread-1 has completed its task
Thread-0 has completed its task
All workers have completed their tasks

C:\>java CountDownLatchDemo
Thread-1 has completed its task
Thread-0 has completed its task
Thread-2 has completed its task
All workers have completed their tasks

*/

Semaphore

A Semaphore is a counting synchronization mechanism that controls access to a resource with a limited number of permits.

It is used when:

  • You want to limit concurrent access to a resource (like threads accessing a database or printing job).
  • You need to implement resource pools, rate limiting, etc.
How It Works
  • Created with a number of permits.
  • Threads call acquire() to get a permit.
  • Call release() when done, returning the permit.
Constructors
public Semaphore(int permits)
Creates a semaphore with the given number of permits and non-fair ordering.

public Semaphore(int permits, boolean fair)
Creates a semaphore with the given number of permits and a fairness policy:
     true = FIFO granting of permits.
     false = permits can be granted out of order.Code language: PHP (php)
Methods
Method Description
void acquire() Acquires a permit, blocking if necessary until one is available.
void acquire(int permits) Acquires the given number of permits, blocking if necessary.
boolean tryAcquire() Acquires a permit only if one is available at the time of invocation.
boolean tryAcquire(long timeout, TimeUnit unit) Acquires a permit if available within the given time.
void release() Releases a permit, returning it to the semaphore.
void release(int permits) Releases the given number of permits.
int availablePermits() Returns the current number of permits available.
int getQueueLength() Returns the number of threads waiting to acquire.
Program 

This program demonstrates the use of Semaphore in Java, which is a synchronization tool that controls access to a shared resource by multiple threads. It ensures that a specific number of threads can concurrently access a particular resource, while others wait for a permit to become available.

//SemaphoreDemo.java
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
    static class Worker implements Runnable {
        private final Semaphore semaphore;
        Worker(Semaphore semaphore) {
            this.semaphore = semaphore;
        }
        @Override
        public void run() {
            try {
                semaphore.acquire(); // Acquire permit
                System.out.println(Thread.currentThread().getName() + " is accessing the shared resource");
                // Simulate some work
                Thread.sleep((long) (Math.random() * 1000));
                semaphore.release(); // Release permit
                System.out.println(Thread.currentThread().getName() + " has released the permit");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
	public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // Allow 2 permits
        // Create threads
        Thread[] threads = new Thread[5];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new Worker(semaphore));
            threads[i].start();
        }
    }
}

/*

C:\>javac SemaphoreDemo.java

C:\>java SemaphoreDemo
Thread-0 is accessing the shared resource
Thread-2 is accessing the shared resource
Thread-3 is accessing the shared resource
Thread-2 has released the permit
Thread-0 has released the permit
Thread-4 is accessing the shared resource
Thread-3 has released the permit
Thread-1 is accessing the shared resource
Thread-4 has released the permit
Thread-1 has released the permit

C:\>java SemaphoreDemo
Thread-0 is accessing the shared resource
Thread-2 is accessing the shared resource
Thread-3 is accessing the shared resource
Thread-2 has released the permit
Thread-3 has released the permit
Thread-4 is accessing the shared resource
Thread-0 has released the permit
Thread-1 is accessing the shared resource
Thread-4 has released the permit
Thread-1 has released the permit

C:\>java SemaphoreDemo
Thread-0 is accessing the shared resource
Thread-1 is accessing the shared resource
Thread-4 is accessing the shared resource
Thread-0 has released the permit
Thread-1 has released the permit
Thread-2 is accessing the shared resource
Thread-4 has released the permit
Thread-3 is accessing the shared resource
Thread-2 has released the permit
Thread-3 has released the permit

*/
Feature CountDownLatch Semaphore
Purpose Waiting for a set of threads to finish or for an event to occur Controlling access to a shared resource, limiting concurrent access
Count/Permits Single count, can only be decremented Counter of permits, can be incremented or decremented
Reusability No, it is a one-time use tool Yes, reusable over time
Blocking Behavior Blocks threads until the count reaches zero Blocks threads if no permits are available
State Countdown state, once it reaches zero, it can’t be reused Permits are available until released, can be adjusted dynamically
Thread Coordination Used to synchronize threads, waiting for all to complete before proceeding Used to limit the number of threads accessing a shared resource at the same time
Use Case Synchronizing threads, such as waiting for workers to complete their tasks Limiting concurrent access to a resource (e.g., managing a connection pool)
Acquisition Mechanism countDown() is used to decrement the count acquire() is used to acquire a permit and release() to release a permit
Post-Completion State Once count reaches zero, it cannot be reset Permits can be acquired and released multiple times
Thread Safety Ensures that all threads wait for the countdown to reach zero Ensures limited access to shared resources by controlling the number of concurrent threads

CountDownLatch and Semaphore are both powerful tools for managing synchronization in concurrent programming in Java, offering different capabilities suited to various synchronization needs.

Scroll to Top