Монитор в Java

У каждого Java-объекта есть связанный с ним intrinsic monitor. Концептуально он объединяет:

  • блокировку с единственным владельцем;
  • счетчик реентерабельных входов;
  • набор потоков, ожидающих через wait().

Это не список «всех синхронизаторов»: Semaphore, CountDownLatch и ReentrantLock — отдельные механизмы.

private final Object monitor = new Object();
private boolean ready;
 
void awaitReady() throws InterruptedException {
    synchronized (monitor) {
        while (!ready) {
            monitor.wait();
        }
    }
}
 
void markReady() {
    synchronized (monitor) {
        ready = true;
        monitor.notifyAll();
    }
}

synchronized (monitor) захватывает монитор. wait() временно освобождает именно его. notifyAll() переводит ожидающих в борьбу за повторный захват; вызывающий поток продолжает владеть монитором до выхода из блока.

Какой объект является монитором

  • у synchronized instance-метода — this;
  • у static synchronized — CurrentClass.class;
  • у блока — выражение в synchronized (expression).

Синхронизация работает только при совпадении объекта по идентичности. Два равных через equals() объекта — два разных монитора.

Не стоит использовать публичные строки, boxed numbers или this библиотеки как lock: внешний код способен захватить тот же объект. Предпочтителен private final Object lock = new Object().

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

  • Монитор и mutex — одно и то же? Monitor включает mutual exclusion и механизм ожидания условия; mutex описывает только взаимное исключение.
  • Освобождает ли notifyAll() monitor? Нет, только выход из synchronized.
  • Совпадают ли мониторы равных объектов? Нет, важна идентичность.
  • Где ждут потоки wait()? В wait set конкретного объекта.