Этот вопрос проверяет понимание механизма повторного входа (reentrancy) в synchronized-методах и блоках Java, что важно для предотвращения взаимоблокировок (deadlocks) при рекурсивных вызовах.
В Java ключевое слово synchronized используется для обеспечения синхронизации потоков, гарантируя, что только один поток может выполнять определённый блок кода или метод объекта в данный момент времени. Это достигается путём захвата монитора (внутренней блокировки), связанного с объектом.
Реентерабельная блокировка (reentrant lock) — это блокировка, которая позволяет потоку, уже владеющему ею, снова её захватить. Это критически важно для ситуаций, где синхронизированный код может вызывать сам себя, например, при рекурсии или когда один синхронизированный метод вызывает другой синхронизированный метод того же объекта.
Каждый объект в Java имеет связанный с ним счётчик вхождений (entry count) для монитора. Когда поток впервые входит в synchronized-блок для объекта, счётчик устанавливается в 1, и поток становится владельцем монитора. Если тот же поток снова входит в synchronized-блок для того же объекта, счётчик увеличивается. При выходе из блока счётчик уменьшается, и когда он достигает нуля, монитор освобождается, позволяя другим потокам захватить его.
public class ReentrantExample {
public synchronized void outerMethod() {
System.out.println("Внешний метод, владею монитором.");
innerMethod(); // Рекурсивный вызов другого synchronized-метода
}
public synchronized void innerMethod() {
System.out.println("Внутренний метод, тот же поток входит снова.");
}
public static void main(String[] args) {
ReentrantExample obj = new ReentrantExample();
// Один поток вызовет оба метода
new Thread(() -> obj.outerMethod()).start();
}
}В этом примере поток, вызвав outerMethod(), захватывает монитор объекта obj. При вызове innerMethod() из outerMethod() тот же поток успешно входит, потому что synchronized реентерабелен. Без реентерабельности это привело бы к deadlock.
super.method().Вывод: Реентерабельность synchronized в Java — это важное свойство, которое предотвращает самоблокировку потоков и упрощает разработку многопоточных приложений, особенно при использовании рекурсии или сложных цепочек вызовов внутри одного объекта. Это делает synchronized более безопасным и удобным для базовых сценариев синхронизации.