What does the synchronized keyword do, and what's the difference between synchronizing a method vs a block?

9 minintermediatesynchronizedlocksconcurrency

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).