0% found this document useful (0 votes)
5 views12 pages

Java Concurrency Notes

This document provides an overview of Java concurrency tools, specifically Semaphore and CountDownLatch. A Semaphore controls the number of threads accessing a resource simultaneously, while a CountDownLatch allows one or more threads to wait until a set of other threads have completed their tasks. Key differences, usage scenarios, and example code for both tools are included to illustrate their functionality.

Uploaded by

ak78679200
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views12 pages

Java Concurrency Notes

This document provides an overview of Java concurrency tools, specifically Semaphore and CountDownLatch. A Semaphore controls the number of threads accessing a resource simultaneously, while a CountDownLatch allows one or more threads to wait until a set of other threads have completed their tasks. Key differences, usage scenarios, and example code for both tools are included to illustrate their functionality.

Uploaded by

ak78679200
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Java Concurrency

Study Notes: Semaphore & CountDownLatch

[Link] | Thread Safety | Beginner-Friendly


Chapter 1 — Semaphore
What is a Semaphore?
A Semaphore is a concurrency tool that controls how many threads can access a shared resource at the same
time. Think of it like a bouncer at a club with a fixed capacity — only N people are allowed inside at once. When
someone leaves, the next person in line can enter.

It works with an internal permit counter:

• acquire() — Takes a permit (decrements the counter). If no permit is available, the thread waits.
• release() — Returns a permit (increments the counter), allowing one waiting thread to proceed.

■ Real-world analogy: A computer lab with only 3 computers and 5 students. The lab monitor holds
3 keys. Students who get a key use a computer; others wait outside until a key is returned.

Import Used
import [Link];

This is a built-in Java class — no external library needed. It lives inside [Link], the standard
package for multi-threading tools introduced in Java 5.

Full Code
import [Link];

public class SemaphoreDemo {

// Only 3 threads can access the resource at once

private static Semaphore bouncer = new Semaphore(3);

static class Person extends Thread {

String name;

Person(String name) { [Link] = name; }

@Override

public void run() {

try {

[Link](name + " is waiting for a computer...");

[Link](); // Block if no permits


[Link](name + " got a computer!");

[Link](2000); // Use computer 2 sec

[Link](name + " is leaving.");

} catch (InterruptedException e) {

[Link]();

} finally {

[Link](); // Always return permit

public static void main(String[] args) {

for (int i = 1; i <= 5; i++) {

new Person("Person " + i).start();

Step-by-Step Explanation
Step 1 — Create the Semaphore
private static Semaphore bouncer = new Semaphore(3);

Keyword Meaning

private Only this class can use it

static Shared by ALL threads — one bouncer for everyone

Semaphore The data type

bouncer Our variable name

new Semaphore(3) Start with 3 permits (3 computers available)

Step 2 — Person extends Thread


static class Person extends Thread { ... }

By writing extends Thread, each Person becomes its own independent thread. This means multiple Persons
can run at the same time — just like multiple students walking into the lab simultaneously.

Step 3 — acquire() — The Gate


[Link]();

• If a permit is available → thread gets it and moves forward instantly.


• If no permits left → thread stops and waits here until one is released.
• This is what causes Person 4 and 5 to wait while 1, 2, 3 use computers.

Step 4 — [Link]() — Simulating Work


[Link](2000); // 2000 ms = 2 seconds

Pauses the thread for 2 seconds to simulate real work (reading a file, calling an API, etc.).

Step 5 — finally + release() — The Exit


finally {

[Link]();

The finally block always runs — even if an exception is thrown. Putting release() here guarantees the permit is
returned no matter what. If we forgot this, waiting threads would be stuck forever (a deadlock).

Step 6 — main() — Launching 5 Threads


for (int i = 1; i <= 5; i++) {

new Person("Person " + i).start();

Creates and starts 5 Person threads simultaneously. The first 3 acquire permits right away; the remaining 2
block on acquire() until a permit is freed.

Visual Flow
Computers (max 3): [ P1 ][ P2 ][ P3 ] <- using computers

Waiting: P4, P5 <- blocked on acquire()

P1 finishes -> release() -> counter: 2->3

[ P4 ][ P2 ][ P3 ] <- P4 unblocks

P5 <- still waiting

P2 finishes -> release() -> counter: 2->3

[ P4 ][ P5 ][ P3 ] <- P5 unblocks

(no one left waiting)

Quick Reference Table


Method / Concept What it does
new Semaphore(N) Create semaphore allowing N concurrent threads

acquire() Enter — decrement counter, wait if 0

release() Exit — increment counter, wake a waiting thread

finally block Ensures release() is ALWAYS called

extends Thread Makes the class run as an independent thread


Chapter 2 — CountDownLatch
What is a CountDownLatch?
A CountDownLatch is a concurrency tool that makes one (or more) threads wait until a set of other threads
have all finished their work. It works like a countdown timer — it starts at N and counts down to 0. When it hits
0, the waiting thread wakes up and continues.

■■ Real-world analogy: A manager waiting for 3 workers to prepare a construction site. The
manager cannot start building until ALL 3 workers are done with their preparations.

Semaphore vs CountDownLatch — Key Difference


Feature Semaphore vs CountDownLatch

Purpose Semaphore: LIMIT threads at once | Latch: WAIT for threads to finish

Analogy Semaphore: Bouncer with tokens | Latch: Manager waiting for workers

Main methods Semaphore: acquire() / release() | Latch: await() / countDown()

Reusable? Semaphore: Yes | Latch: No (one-time use)

Who waits? Semaphore: Incoming threads | Latch: The controlling thread

Import Used
import [Link];

Also built-in to [Link] — no external libraries needed.

Full Code
import [Link];

public class LatchDemo {

public static void main(String[] args) {

CountDownLatch latch = new CountDownLatch(3); // counter starts at 3

for (int i = 1; i <= 3; i++) {

new Thread(new Worker(i, latch)).start(); // start 3 workers


}

try {

[Link]("MANAGER: Waiting for workers...");

[Link](); // STOP until counter = 0

[Link]("MANAGER: All done. Starting Project!");

} catch (InterruptedException e) {

[Link]();

static class Worker implements Runnable {

private int id;

private CountDownLatch latch;

Worker(int id, CountDownLatch latch) {

[Link] = id;

[Link] = latch;

@Override

public void run() {

try {

[Link]("Worker " + id + " is doing a task...");

[Link](2000); // simulate 2s of work

[Link]("Worker " + id + " is done.");

[Link](); // reduce counter by 1

} catch (InterruptedException e) {

[Link]();

Step-by-Step Explanation
Step 1 — Create the Latch
CountDownLatch latch = new CountDownLatch(3);

Creates a latch with its counter set to 3. Think of it as a checklist with 3 items that must all be ticked before work
can begin.

Counter: [3] -> Worker 1 done -> [2] -> Worker 2 done -> [1] -> Worker 3 done -> [0]

When the counter reaches 0, the waiting manager thread wakes up.

Step 2 — implements Runnable vs extends Thread


Approach How threads are created

extends Thread class IS a thread. Start with: new Person().start()

implements Runnable class is a TASK. Wrap it: new Thread(new Worker()).start()

Both are valid. implements Runnable is generally preferred because Java only allows one class to be
extended, so using Runnable keeps your options open.

Step 3 — Passing the Latch to Workers


Worker(int id, CountDownLatch latch) {

[Link] = id;

[Link] = latch;

The same latch object is passed to all 3 workers and the manager. They all look at the same counter — this
shared reference is what makes coordination possible.

Step 4 — await() — The Manager Waits


[Link]();

• The manager thread STOPS here and does nothing.


• It will only continue when the latch counter reaches exactly 0.
• Think of it as: "I'll wait right here until everyone checks in."

Step 5 — countDown() — Workers Signal Completion


[Link]();

• Each worker calls this after finishing its task.


• This reduces the latch counter by 1.
• When all 3 workers call it, counter hits 0 → manager wakes up.
• Important: countDown() never blocks — it just decrements and continues.

Step 6 — try-catch for InterruptedException


try { ... }

catch (InterruptedException e) { [Link](); }


Both await() and [Link]() can throw InterruptedException if the thread is forcefully stopped. The catch
block handles this gracefully by printing the error details.

Visual Flow
main() starts

+-- Latch created: counter = 3

+-- Worker 1 started (runs independently)

+-- Worker 2 started (runs independently)

+-- Worker 3 started (runs independently)

+-- Manager hits [Link]() --> STOPS and waits

Worker 1 -> works 2s -> countDown() -> counter: 3->2

Worker 2 -> works 2s -> countDown() -> counter: 2->1

Worker 3 -> works 2s -> countDown() -> counter: 1->0

counter = 0 --> Manager WAKES UP

Manager prints "All done. Starting Project!"

Program ends

Important Limitation
■■ CountDownLatch is NOT reusable. Once the counter reaches 0, it stays at 0 forever. If you
need a latch that can reset and be used again, Java provides CyclicBarrier — a similar tool that can
be reused multiple times.

Feature CountDownLatch vs CyclicBarrier

Reusable? CountDownLatch: No | CyclicBarrier: Yes

Who waits? CountDownLatch: One thread waits for many | CyclicBarrier: All threads wait for each other

Use case CountDownLatch: Manager waits for workers | CyclicBarrier: All runners wait at starting line
Quick Reference Table
Method / Concept What it does

new CountDownLatch(N) Create a latch with counter starting at N

await() Block the current thread until counter reaches 0

countDown() Reduce the counter by 1 (never blocks)

implements Runnable Alternative to extends Thread; wraps task in new Thread()

[Link] = latch Store shared latch reference in each worker


Chapter 3 — Comparison & Summary
Side-by-Side Comparison
Topic Semaphore vs CountDownLatch

Goal Limit simultaneous access vs Wait for completion

Counter goes Up and Down (permits in/out) vs Only Down (0 and done)

Who blocks? Incoming threads block vs The waiting manager blocks

Reusable? Yes vs No

Key methods acquire() / release() vs await() / countDown()

Analogy Bouncer with N tokens vs Manager with N-item checklist

When to Use Which?


Situation Use

Limit DB connections to max 5 at once Semaphore(5)

Wait for 3 services to start before app boots CountDownLatch(3)

Allow only 2 threads to write a file at once Semaphore(2)

Wait for all workers to finish before reporting CountDownLatch(N)

Control access to a shared printer pool Semaphore(printerCount)

Key Java Concepts Covered


Concept Explanation

Thread An independent unit of execution running alongside others

extends Thread Makes a class into a thread directly

implements Runnable Defines a task; must be wrapped in new Thread()

start() Launches the thread; internally calls run()

run() The code the thread actually executes

[Link](ms) Pauses the current thread for given milliseconds


try-catch-finally Error handling; finally always runs

static Shared across all instances/threads

this.x = x Assigns a constructor parameter to the object's own field

Quick Cheat Sheet


SEMAPHORE COUNTDOWNLATCH

--------- --------------

new Semaphore(N) new CountDownLatch(N)

-> N permits available -> Counter starts at N

[Link]() [Link]()

-> Get a permit -> Block until counter == 0

-> Block if none available

[Link]() [Link]()

-> Return a permit -> Reduce counter by 1

-> Wake a waiting thread -> Never blocks

Use: limit concurrency Use: coordinate completion

■ You have now learned: Semaphore (limit concurrent access) and CountDownLatch (wait for all
tasks to complete) — two of the most important building blocks in Java multi-threaded programming.

You might also like