CountDownLatch and Other Synchronizers

The Synchronizers

ClassIdeaExample
CountDownLatchwait until N events happened (one-shot)start the app after 3 services are ready
CyclicBarrierN threads wait for each other, reusablegame round starts when all players are ready
Semaphoreat most N permits at a timemax 10 DB connections, rate limits
Phaserflexible multi-phase barriermulti-step batch jobs
Exchangertwo threads swap objectsdouble buffering

CountDownLatch: Wait for Startup Checks

Example

Workers record their result in a thread-safe list; main prints after await(), sorted, so output is stable.

import java.util.*;
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        List<String> checks = List.of("database", "redis", "payment-gateway");
        CountDownLatch ready = new CountDownLatch(checks.size());
        Queue<String> results = new ConcurrentLinkedQueue<>();

        for (String c : checks) {
            Thread.ofPlatform().start(() -> {
                results.add(c + " OK");
                ready.countDown();
            });
        }
        boolean allReady = ready.await(5, TimeUnit.SECONDS);
        results.stream().sorted().forEach(System.out::println);
        System.out.println("All checks passed: " + allReady + " -> starting server");
    }
}

Output

database OK
payment-gateway OK
redis OK
All checks passed: true -> starting server

Semaphore: Limit Concurrency

Example

10 tasks share an API that allows only 3 calls at a time. The program tracks the highest number of simultaneous calls.

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class Main {
    public static void main(String[] args) {
        Semaphore permits = new Semaphore(3);
        AtomicInteger inFlight = new AtomicInteger();
        AtomicInteger maxSeen = new AtomicInteger();
        AtomicInteger done = new AtomicInteger();

        try (ExecutorService pool = Executors.newFixedThreadPool(10)) {
            for (int i = 0; i < 10; i++) {
                pool.submit(() -> {
                    try {
                        permits.acquire();
                        try {
                            int now = inFlight.incrementAndGet();
                            maxSeen.accumulateAndGet(now, Math::max);
                            Thread.sleep(50);
                            inFlight.decrementAndGet();
                            done.incrementAndGet();
                        } finally { permits.release(); }
                    } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
                });
            }
        }
        System.out.println("Calls done: " + done.get());
        System.out.println("Never more than 3 at once: " + (maxSeen.get() <= 3));
    }
}

Output

Calls done: 10
Never more than 3 at once: true