synchronized

The synchronized keyword enforces mutual exclusion: only one thread can execute a given synchronized block or method at a time on the same monitor object. It is Java's oldest concurrency primitive and still widely used.

Synchronized method

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
    public synchronized int get() {
        return count;
    }
}

Locks the instance (this). Only one thread at a time can call increment or get on a given Counter.

Synchronized block

private final Object lock = new Object();

public void doWork() {
    synchronized (lock) {
        // only one thread at a time enters this block
    }
}

Finer control β€” lock on a dedicated object, not the entire instance.

Alternatives for modern code

  • ReentrantLock β€” more flexible, supports tryLock, fairness.
  • Atomic classes β€” AtomicInteger, AtomicLong for simple counters.
  • ConcurrentHashMap β€” for concurrent maps instead of synchronizedMap.
  • Immutable objects β€” no synchronisation needed at all.

synchronized + virtual threads

Before Java 21, synchronized could pin a virtual thread to its carrier, hurting scalability. Java 21 and later mostly fix this, but many teams now prefer ReentrantLock specifically to avoid pinning edge cases.