Concurrency
Locks & Synchronization
synchronized couples mutual exclusion with visibility, per object monitor, automatically released. ReentrantLock adds tryLock, timeouts, interruptibility, and fairness; ReadWriteLock and StampedLock optimize read-heavy access.- Every object has a monitor;
synchronized(obj)/ synchronized methods acquire it, re-entrantly - Static synchronized methods lock on the Class object — a different lock than instances
- Keep critical sections small; never call alien methods or do I/O while holding a lock (EJ 79)
ReentrantLockwhen you need tryLock/timeout/interruptible/fair — elsesynchronizedis fineReadWriteLock: many concurrent readers OR one writer;StampedLockadds optimistic reads- Lock on a
private final Object lockto prevent outsiders locking your monitor
public class Vault {
private final Object lock = new Object(); // private lock object: uninterferable
private final Map<String, byte[]> secrets = new HashMap<>();
public void store(String id, byte[] value) {
byte[] copy = value.clone(); // work OUTSIDE the lock
synchronized (lock) {
secrets.put(id, copy); // only the shared-state touch inside
}
}
}Monitors are reentrant: a thread holding the lock may re-acquire it (synchronized method calling another synchronized method of the same object) — without reentrancy that would self-deadlock. The lock releases automatically on exit, exception or not. Modern JVMs make uncontended synchronized extremely cheap (biased/thin locks; see Concurrent Performance); contention, not the keyword, is what costs.
private final ReentrantLock lock = new ReentrantLock();
public boolean transfer(Account to, long amount) throws InterruptedException {
if (lock.tryLock(1, TimeUnit.SECONDS)) { // give up instead of deadlocking
try {
balance -= amount;
to.deposit(amount);
return true;
} finally {
lock.unlock(); // ALWAYS in finally
}
}
return false;
}private final ReadWriteLock rw = new ReentrantReadWriteLock();
public Config read() {
rw.readLock().lock(); // readers share
try { return snapshot(); } finally { rw.readLock().unlock(); }
}
public void update(Config c) {
rw.writeLock().lock(); // writer excludes everyone
try { apply(c); } finally { rw.writeLock().unlock(); }
}