Method of creating a thread in Java
- Extend the thread class → Override the
run()method- Con: You cannot extend any other class
- Implement runnable and pass it to the constructor of the thread class (recommended)
- Pros: more flexible and we can extend other classes
- Cons:
run()method cannot return a result or throw checked exceptions- The run function is a void and cannot return some value or throw exceptions which can lead to race conditions or silent failures
- The solution is
callableandfuture> return type isGenerics
Keywords
volatilekeyword is used to tell a thread that a variable should not be cached and can be changed by any other thread- ensure memory visibility but not atomicity
synchronizedkeyword ensures that only one thread can execute a specific block of code at a time, preventing thread interference- NOT to be used when:
- high concurrency scaling
- read-heavy workloads > use
ReentrantReadWriteLockinstead - simple increments > use
AtomicIntegerinstead - if you need to lock two objects and release them in a specific order > use
ReentrantLock
- Common types of keys for
synchronizedthis- current instance - the object that is calling the function- private dedicated lock - create specific objects to act as keys for specific pieces of data
ClassName.class- a global key that locks the entire class for every instance- external locking - synchronize two different classes based on a shared resource
- NOT to be used when:
waitandnotifykeywords
Thread Pools
Executor Framework - Managing Threads
CountDownLatch
1. Summary: What is CountDownLatch?
A CountDownLatch is a concurrency utility that allows one or more threads to wait until a set of operations performed in other threads completes. It works like a “one-way gate”:
- It is initialized with a count.
- The
await()method blocks until the count reaches zero. - The
countDown()method decrements the counter. - Once the count reaches zero, the gate opens and cannot be reset.
2. Practical Use Cases
- Service Startup Dependency: Ensuring a main application server only starts after its required modules (e.g., Database, Cache, Messaging Queue) have signaled they are ready.
- Parallel Test Execution: Waiting for multiple parallel test cases to finish before generating a final aggregate report.
- The “Starting Gun”: Initializing several threads and having them all wait on a latch with a count of 1. When the main thread calls
countDown(), all threads start simultaneously.
3. Brief Code Example
This example demonstrates a Main Task waiting for three Worker Tasks to finish. Java
import java.util.concurrent.CountDownLatch;
public class LatchExample {
public static void main(String[] args) throws InterruptedException {
int workerCount = 3;
CountDownLatch latch = new CountDownLatch(workerCount);
for (int i = 1; i <= workerCount; i++) {
new Thread(new Worker(i, latch)).start();
}
System.out.println("Main thread is waiting for workers...");
latch.await(); // Blocks until count is 0
System.out.println("All workers finished. Main thread proceeding.");
}
}
class Worker implements Runnable {
private final int id;
private final CountDownLatch latch;
Worker(int id, CountDownLatch latch) { this.id = id; this.latch = latch; }
public void run() {
System.out.println("Worker " + id + " is doing work.");
latch.countDown(); // Decrements the count
}
}4. When to Use vs. When Not to Use
Use it when:
- You have a one-time synchronization point.
- You need one thread to wait for different events (even if those events happen on the same thread).
- The number of operations is known at the time of initialization.
Do NOT use it when:
- You need to reuse the latch: If you need the counter to reset after it reaches zero (e.g., in a recurring algorithm), use a
CyclicBarrier. - Dynamic parties: If the number of threads/tasks changes during execution, a
Phaseris more flexible. - Complex state sharing: If you need to pass data between threads as they wait, consider a
CompletableFutureorExchanger. TODO: - Callable and Future
- Read about Generics
- Virtual Threads in Java 21+
- Dealing with shared data (Synchronization)
synchronized- Reentrant Lock
- Atomic
- Concurrent Collections