Чем synchronized на статическом методе отличается от synchronized на методе экземпляра

Монитор — это объект, на который вешается блокировка, и от него зависит всё поведение synchronized.

У instance-метода synchronized лочит this — конкретный объект. У static synchronized метода монитор — объект Class самого класса, один на все инстансы. Два потока, работающие с разными объектами класса, через instance synchronized вообще не блокируют друг друга, а через static synchronized — блокируют, даже если работают с разными данными.

Ловушка в смешивании уровней:

public class Counter { private static int total = 0;

public synchronized void inc() { total++; } }

Метод синхронизирован по this, а поле total — static, общее для всех инстансов. Два разных объекта Counter, вызывающих inc() из разных потоков, спокойно проходят synchronized параллельно и гонятся за одним и тем же total.

Спросят, как починить: либо synchronized (Counter.class), либо сделать сам метод static synchronized, либо взять AtomicInteger. Дальше могут уточнить про вложенные static-блоки в разных классах — у каждого класса свой Class-объект, они друг друга не блокируют.

Synchronized защищает не переменную, а участок кода вокруг конкретного монитора. Выбрали неправильный монитор — блокировки просто нет, хотя код выглядит потокобезопасным.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки