Threading Primitives
Low-level concurrency building blocks in java.lang and java.util.concurrent.locks.
At a Glance
synchronized— Built-in monitor lock. Simplest way to make a block or method thread-safe. Reentrant. No fairness control, no interruptible lock acquisition, no try-lock.volatile— Guarantees visibility of a field across threads (no caching in CPU registers). Does not provide atomicity for compound operations likei++. Use for flags and single-writer fields.ReentrantLock— Explicit lock withtryLock, timed waits, interruptibility, and optional fairness. More flexible thansynchronized, but you must manually unlock in a finally block.ReadWriteLock— Separate read and write locks. Multiple concurrent readers, exclusive writer. Use when reads vastly outnumber writes.StampedLock— Optimistic read lock for highest-throughput read-heavy scenarios. Not reentrant. More complex API thanReadWriteLock.Condition— Replacement forwait()/notify()tied to a specificLock. Supports multiple wait-sets per lock.AtomicInteger,AtomicLong,AtomicReference— Lock-free atomic operations via CAS. Use for counters, flags, and lock-free data structures.CountDownLatch— One-shot barrier. N threads count down; waiting threads proceed when count reaches zero. Cannot be reset.CyclicBarrier— Reusable barrier. N threads wait until all arrive, then all proceed. Can be reset and reused across phases.Semaphore— Counting permit system. Controls access to a limited number of resources. Supports fairness.Phaser— Flexible barrier for variable numbers of parties. Supports multiple phases and dynamic registration/deregistration.
synchronized
Intrinsic monitor lock. Reentrant and exclusive.
// Synchronized method — locks on 'this'
public synchronized void increment() {
count++;
}
// Synchronized block — locks on specific object
public void increment() {
synchronized (this) {
count++;
}
}
// Lock on a private object (preferred — prevents external interference)
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
// Static synchronized — locks on the Class object
public static synchronized void doSomething() {
// ...
} wait / notify
// Producer-consumer with wait/notify
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // releases lock, suspends thread
}
item = queue.poll();
}
// Producer side
synchronized (lock) {
queue.add(item);
lock.notifyAll(); // wake all waiting threads
}
// Always use notifyAll() over notify() — notify() can miss threads
// Always wait in a while loop — guards against spurious wakeups volatile
Visibility guarantee without locking.
// Common pattern: shutdown flag
private volatile boolean running = true;
// Writer thread
public void stop() {
running = false;
}
// Reader thread
public void run() {
while (running) {
doWork();
}
} volatile | synchronized | |
|---|---|---|
| Visibility | Yes | Yes |
| Atomicity | No (single read/write only) | Yes (entire block) |
| Blocking | Never | Can block |
| Use case | Flags, published references | Compound operations |
ReentrantLock
Explicit lock with advanced features.
private final ReentrantLock lock = new ReentrantLock();
// Basic usage — always unlock in finally
lock.lock();
try {
// critical section
} finally {
lock.unlock();
}
// Try-lock — non-blocking attempt
if (lock.tryLock()) {
try {
// got the lock
} finally {
lock.unlock();
}
} else {
// lock not available — do something else
}
// Timed try-lock
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// ...
} finally {
lock.unlock();
}
}
// Fair lock — threads acquire in FIFO order (lower throughput)
ReentrantLock fairLock = new ReentrantLock(true); ReadWriteLock
Multiple concurrent readers, exclusive writer.
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
// Multiple threads can read concurrently
public String read() {
readLock.lock();
try {
return data;
} finally {
readLock.unlock();
}
}
// Only one thread can write; blocks all readers
public void write(String value) {
writeLock.lock();
try {
data = value;
} finally {
writeLock.unlock();
}
} StampedLock
Optimistic reads for highest throughput. Java 8+. Not reentrant.
private final StampedLock sl = new StampedLock();
private double x, y;
// Optimistic read — no blocking, validate afterward
public double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
double cx = x, cy = y;
if (!sl.validate(stamp)) {
// data changed — fall back to read lock
stamp = sl.readLock();
try {
cx = x;
cy = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(cx * cx + cy * cy);
}
// Write lock
public void move(double dx, double dy) {
long stamp = sl.writeLock();
try {
x += dx;
y += dy;
} finally {
sl.unlockWrite(stamp);
}
} Condition
Like wait()/notify() but tied to a specific Lock. Multiple wait-sets per lock.
private final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
public void put(E item) throws InterruptedException {
lock.lock();
try {
while (count == capacity) notFull.await();
enqueue(item);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
lock.lock();
try {
while (count == 0) notEmpty.await();
E item = dequeue();
notFull.signal();
return item;
} finally {
lock.unlock();
}
} Atomic Classes
Lock-free thread-safe operations via CAS (compare-and-swap).
| Class | Type | Key Methods |
|---|---|---|
AtomicInteger | int | get, set, incrementAndGet, compareAndSet |
AtomicLong | long | Same as AtomicInteger |
AtomicBoolean | boolean | get, set, compareAndSet |
AtomicReference<V> | object ref | get, set, compareAndSet, updateAndGet |
LongAdder | long (striped) | add, sum — higher throughput than AtomicLong under contention |
LongAccumulator | long (striped) | Generalized LongAdder with custom accumulation function |
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // 1
counter.addAndGet(5); // 6
counter.compareAndSet(6, 10); // true, now 10
// CAS loop pattern
AtomicInteger val = new AtomicInteger(0);
int prev, next;
do {
prev = val.get();
next = prev + 1;
} while (!val.compareAndSet(prev, next));
// Or use updateAndGet
val.updateAndGet(v -> v + 1);
// LongAdder — better than AtomicLong for high-contention counters
LongAdder adder = new LongAdder();
adder.add(1); // called from many threads
adder.sum(); // read the total Synchronizers
CountDownLatch
One-shot: N threads count down, waiters proceed at zero.
CountDownLatch latch = new CountDownLatch(3);
// Worker threads
Runnable worker = () -> {
doWork();
latch.countDown(); // decrement count
};
// Main thread waits for all workers
latch.await();
// or with timeout:
latch.await(10, TimeUnit.SECONDS); CyclicBarrier
Reusable: all N threads wait, then all proceed together.
// Optional barrier action runs when all threads arrive
CyclicBarrier barrier = new CyclicBarrier(3, () ->
System.out.println("All threads arrived"));
Runnable worker = () -> {
phase1();
barrier.await(); // wait for others
phase2();
barrier.await(); // reusable — works again
}; Semaphore
Counting permits — limit concurrent access to a resource.
// At most 5 concurrent connections
Semaphore pool = new Semaphore(5);
pool.acquire(); // blocks if no permits
try {
useConnection();
} finally {
pool.release();
}
// Non-blocking
if (pool.tryAcquire()) {
try {
useConnection();
} finally {
pool.release();
}
} Thread Basics
// Creating threads
Thread t1 = new Thread(() -> doWork());
t1.start();
// Naming (useful for debugging)
Thread t2 = new Thread(() -> doWork(), "worker-1");
// Daemon threads — JVM exits when only daemons remain
Thread t3 = new Thread(() -> doWork());
t3.setDaemon(true);
t3.start();
// Waiting for a thread to finish
t1.join();
t1.join(5000); // with timeout (ms)
// Interruption — cooperative cancellation
t1.interrupt();
// Inside the target thread
while (!Thread.currentThread().isInterrupted()) {
doWork();
}
// Thread.sleep throws InterruptedException
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore flag
}