Single-Liners for Quick Brush-Up
Mutex (Mutual Exclusion)
A lock ensuring only one thread enters a critical section at a time, featuring strict ownership (only the locker can unlock).
Semaphore
A signaling mechanism using an integer counter to manage access to a pool of resources (a mutex is just a semaphore initialized to 1)
Monitor
A higher-level synchronization pattern bundling a mutex with condition variables (
wait/notify) for automatic thread coordination.
synchronized
Java’s native implementation of a monitor lock backed by an object’s header (Mark Word).
Race Condition
A bug where multiple threads access shared mutable state simultaneously, and the output depends on non-deterministic thread scheduling
Deadlock
A state where two or more threads freeze permanently, each waiting for a lock held by the other in a circular dependency.
Virtual Threads (Project Loom)
Lightweight user-mode threads managed by the JVM, eliminating the need for manual thread pools and allowing millions of concurrent tasks.
Core Concurrency Primitives Explained
%%{init: {"theme": "redux-color"}}%% flowchart TD A[Concurrency Primitives] --> B[Mutex / Lock] A --> C[Semaphore] A --> D[Monitor] B --> B1[Strict 1-to-1 Ownership] C --> C1[Multi-permit Counter / Pool] D --> D1[Mutex + Condition Variables / Automatic Management]
The Office Building Analogy
- Mutex: A single restroom with a deadbolt. Only one person goes in, and the person who locks it must be the one to unlock it.
- Semaphore: A media room with 3 computer passes at the front desk. Anyone can grab a pass, use a computer, and anyone can return it.
- Monitor: The restroom managed by an assistant who automatically locks the door for you and puts you to sleep in a corner if you’re waiting for a document.
Java vs. .NET (C#) Cross-Reference
| Concept | Java Equivalent | .NET / C# Equivalent |
|---|---|---|
| Basic Mutual Exclusion | synchronized block / method | lock statement (Monitor.Enter/Exit) |
| Explicit Reentrant Lock | java.util.concurrent.locks.ReentrantLock | System.Threading.Monitor / custom wrappers |
| Resource Pool Control | java.util.concurrent.Semaphore | System.Threading.SemaphoreSlim |
| Cross-Process Mutex | OS File Locking (FileChannel) | System.Threading.Mutex |
The Anatomy of Concurrency Failures
A. Race Conditions
- Definition: Occurs during non-atomic operations (e.g.,
count++breaks into ReadModify Write). - Fix: Use atomic operations (
AtomicInteger), locks (ReentrantLock), or synchronization (synchronized).
B. Deadlocks
- The 4 Conditions: Mutual Exclusion, Hold and Wait, No Preemption, Circular Wait.
- Prevention:
- Global Lock Ordering: Always acquire locks in the exact same sequence across all threads.
- Timeouts: Use
tryLock()instead of infinite blocking.
4. The Evolution of Java Multithreading
timeline title Java Concurrency Evolution Java 1.0 : Raw Threads & synchronized blocks (Heavy, manual, error-prone) Java 5 : java.util.concurrent (ExecutorService, Atomic, Locks, CountDownLatch) Java 8 : CompletableFuture (Asynchronous functional pipelines) Java 21+ : Virtual Threads & Structured Concurrency (Project Loom - JVM managed runtime)
Quick Code Reference: The Modern Standard
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class ModernConcurrencyExample {
public static void main(String[] args) throws InterruptedException {
// Thread-safe map with atomic variables
ConcurrentHashMap<String, AtomicInteger> inventory = new ConcurrentHashMap<>();
inventory.put("Item", new AtomicInteger(100));
// Spawning 1,000 Virtual Threads instantly (Project Loom)
var threads = IntStream.range(0, 1000).mapToObj(i ->
Thread.ofVirtual().unstarted(() -> {
inventory.get("Item").updateAndGet(stock -> (stock > 0) ? stock - 1 : 0);
})
).toList();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
System.out.println("Final Stock: " + inventory.get("Item").get());
}
}