What does the synchronized keyword do, and what's the difference between synchronizing a method vs a block?
Quick Answer
synchronized ensures only one thread at a time can execute a given critical section by acquiring the intrinsic lock (monitor) associated with an object, providing both mutual exclusion and a happens-before memory visibility guarantee. A synchronized instance method locks on 'this'; a synchronized static method locks on the Class object; a synchronized block lets you lock on any explicit object and scope the critical section more narrowly, reducing contention.
Detailed Answer
synchronized provides mutual exclusion: only one thread can hold a given object's intrinsic lock (monitor) at a time, so code guarded by the same lock never runs concurrently across threads. It also establishes a happens-before relationship — changes made by a thread before releasing the lock are guaranteed visible to the next thread that acquires the same lock, which matters as much as the mutual exclusion itself.
Synchronized instance method — locks on this (the current object):
class Counter {
private int count;
synchronized void increment() { count++; } // locks on `this`
}
Synchronized static method — locks on the Class object itself (shared across all instances):
class Registry {
static synchronized void register(String name) { /* locks on Registry.class */ }
}
Synchronized block — locks on any explicit object you choose, letting you scope the critical section as narrowly as possible (reducing how long the lock is held, and thus contention):
class Cache {
private final Object lock = new Object();
private Map<String, String> data = new HashMap<>();
void put(String k, String v) {
// ... some non-critical work here, unsynchronized ...
synchronized (lock) {
data.put(k, v); // only this part needs the lock
}
}
}
Why prefer blocks over whole-method synchronization: synchronizing an entire method locks for its whole duration, even parts that don't touch shared state — a synchronized block using a dedicated private lock object minimizes contention and avoids accidentally exposing your lock object to external code that could lock on it unexpectedly (a risk when synchronizing on this in a public API).