Подтвердить что ты не робот

Синхронизированный метод вызывает себя рекурсивно. Это сломано?

Цель этого вопроса - проиллюстрировать, что Java работает не так, как я ожидал.

Как вы ожидаете, что следующий код будет вести себя?

public class SynchTester {
  private static SynchTester synchTester;

  public synchronized static SynchTester getSynchTester(){
    if(synchTester==null){
      synchTester = new SynchTester();
    }

    return synchTester;
  }

  private SynchTester() {
    SynchTester myTester = getSynchTester();
  }

  public static void main(String[] args) {
    SynchTester tester = SynchTester.getSynchTester();
  }
}

Я ожидаю, что он будет висеть с тупиком, ожидающим завершения рекурсии, но вместо этого он бросает StackOverflow. Очевидно, синхронизация не блокирует доступ к тому же потоку.

Это ошибка?

4b9b3361

Ответ 1

В Java синхронизированные блокировки реентерабельны.

Вспомните, что нить не может получить блокировку, принадлежащую другому потоку. Но поток может получить блокировку, которой он уже владеет. Разрешить потоку получать один и тот же замок более одного раза, обеспечивает повторную синхронизацию. Это описывает ситуацию, когда синхронизированный код, прямо или косвенно, вызывает метод, который также содержит синхронизированный код, и оба набора кода используют одну и ту же блокировку. Без повторной синхронизации синхронизированный код должен принять много дополнительных мер предосторожности, чтобы избежать блокировки потока.

Источник: см. нижнюю часть этой страницы

Ответ 2

Синхронизированный метод должен иметь возможность блокировки объекта монитора. Объектом монитора является экземпляр (или класс для статического метода). Нить, которая уже имеет блокировку, не нуждается в ее повторении. Так что да, это может вызвать stackoverflow (harhar).

Ответ 3

из java tutorials:

Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же объекта (приостановить выполнение) до тех пор, пока первый поток не будет выполнен с объектом.

Итак, я думаю, что ключевое слово syncronized работало так, как ожидалось, и синхронизированный рекурсивный вызов совершенно легален (и работает) в java.