Working with Synchronizers

1. Using CountDownLatch

APIUse
new CountDownLatch(n)Initial count
countDown()Decrement
await()Block until 0
One-shotCannot reset

Example: Wait for N workers

var latch = new CountDownLatch(workers);
for (var w : tasks) exec.submit(() -> { try { w.run(); } finally { latch.countDown(); } });
latch.await();

2. Using CyclicBarrier

APIUse
new CyclicBarrier(parties[, action])Synchronization point
await()Wait for all parties
ReusableAuto-resets after trip
BrokenInterrupt or timeout breaks barrier

3. Using Semaphore

APIUse
new Semaphore(permits[, fair])Resource pool
acquire([n])Block for permits
release([n])Return permits
tryAcquire([t, u])Non-blocking / timed

4. Using Exchanger

APIUse
exchange(v)Swap values between two threads
PairBoth threads block until both arrive
UseProducer/consumer buffer swap

5. Using Phaser

APIUse
register / bulkRegisterAdd parties dynamically
arriveAndAwaitAdvanceLike CyclicBarrier
arriveAndDeregisterLeave
PhasesNumbered, multi-stage

6. Understanding Use Cases for Each

SynchronizerBest For
CountDownLatchOne-time wait for N events
CyclicBarrierRepeated all-meet rendezvous
SemaphoreResource limiting / rate limiting
ExchangerPairwise data swap
PhaserDynamic parties + multi-phase

7. Combining Multiple Synchronizers

PatternCombination
Bounded parallelismSemaphore + ExecutorService
Phased pipelinePhaser per stage
Startup gateTwo CountDownLatches (start, done)

8. Avoiding Common Pitfalls

PitfallFix
Forget release() on exceptionUse try/finally
Latch never reaches 0Decrement in finally block
Broken barrierCatch BrokenBarrierException
Deadlock with multiple latchesConsistent ordering

9. Using LockSupport

APIUse
park()Block current thread
parkNanos(t)Timed
unpark(thread)Wake target
PermitPer-thread, single permit
UseBuilding blocks for custom locks

10. Implementing Custom Synchronizers

BaseUse
AbstractQueuedSynchronizerFoundation for ReentrantLock, Semaphore
OverridetryAcquire / tryRelease (exclusive) or shared variants
StateSingle int held by AQS