Рассмотрим метод с синхронизированным блоком (адаптировано из JVMS )
public void foo(Object f) {
synchronized(f) {
doSomething();
}
}
Давайте переведем его на псевдокод (смесь Java и байт-кода !!!):
public void foo(Object f) {
monitorenter(f);
try {
doSomething();
monitorexit(f);
} catch(Throwable e) {
monitorexit(f);
throw e;
}
}
Вот так это будет выглядеть, , если инструкция байт-кода monitorenter
и monitorexit
были бы методами java.
Каждый объект имеет один монитор. Если один поток входит в монитор и монитор не получен (заблокирован, получен), то он получает (блокирует, получает) монитор и вызывает doSomething()
(который является следующей строкой).
Если теперь появляется второй поток и пытается войти в монитор объекта f
, то он ждет в этом месте, пока монитор объекта f
не будет освобожден. Монитор освобождается, когда первый поток вызывает одну из двух monitorexit
инструкций (байт-код !!).
Вернуться к вопросу - сколько мониторов может быть введено одним потоком? Не может быть никаких ограничений (кроме ограничений размера стека). Если doSomething
является другим синхронизированным методом и использует монитор объекта g
, то поток 1 также войдет в этот монитор и получит монитор на g
(если доступно).
Это , а не объект, который получает блокировку, это поток , который входит в монитор объектов, и этот процесс "блокируется".