Почему synchronized-метод на интерфейсе по умолчанию не компилируется
Вопрос звучит просто: можно ли поставить synchronized на default-метод интерфейса? Компилятор отвечает сразу — нет, JLS прямо запрещает модификатор synchronized на методах интерфейса, включая default и static.
Причина не техническая деталь синтаксиса, а концептуальная. У интерфейса нет своего монитора в том смысле, в котором есть у класса — точнее, монитор есть у экземпляра реализующего класса, но интерфейс не знает, каким будет этот класс на момент компиляции. Synchronized требует конкретного объекта-монитора, а интерфейс описывает контракт, а не реализацию с полями и состоянием.
Поэтому если нужна синхронизация внутри default-метода, единственный путь — обычный блок synchronized(this) внутри тела метода, а не модификатор у сигнатуры.
public interface Counter { default void increment() { synchronized (this) { doIncrement(); } }
void doIncrement(); }
Следом спросят: а если несколько классов реализуют этот интерфейс и каждый вызывает increment() параллельно — где именно лок? Правильный ответ: лок на this означает лок на конкретном экземпляре класса-реализации, а не общий для всех реализаций интерфейса. Если нужна общая блокировка на уровне класса, а не инстанса, придётся выносить статический монитор в саму реализацию.
Interface — это контракт без состояния, и synchronized требует состояния. Отсюда и запрет на уровне языка, а не просто договорённость стиля кода.
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки