Ключевое слово synchronized

synchronized захватывает intrinsic monitor объекта. Пока монитор занят, другой поток не войдет в секцию, синхронизированную на том же объекте.

public synchronized void increment() {
    count++;
}

Эквивалентно:

public void increment() {
    synchronized (this) {
        count++;
    }
}

Статический synchronized-метод блокируется на объекте Example.class, а не на экземпляре:

public static synchronized void reset() { /* lock Example.class */ }

Гарантии

  • вход взаимно исключает конкурентов на том же мониторе;
  • выход из блока happens-before последующего входа в блок на том же мониторе;
  • монитор освобождается при обычном выходе и при исключении;
  • блокировка реентерабельна.

Синхронизировать лучше минимальную секцию, сохраняющую инвариант. Медленную сеть и callbacks под монитором по возможности не выполнять: они увеличивают contention и риск deadlock.

private final Object lock = new Object();
 
public Snapshot snapshot() {
    synchronized (lock) {
        return new Snapshot(a, b);
    }
}

Отдельный private lock не позволяет внешнему коду случайно конкурировать на this.

На собеседовании

  • На чем блокируется instance synchronized method? На this.
  • На чем static synchronized? На объекте класса Class.
  • Освободится ли монитор при exception? Да.
  • Реентерабелен ли synchronized? Да.
  • Можно ли прервать поток, ожидающий входа в synchronized? Interrupt выставит флаг, но не отменит ожидание intrinsic monitor.