Чем 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 — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки