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

Безопасно ли вызывать синхронизированный метод из другого синхронизированного метода?

Если синхронизированный метод вызывает другой синхронизированный метод, является ли он безопасным по потоку?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}
4b9b3361

Ответ 1

Да, когда вы отмечаете методы как synchronized, вы действительно это делаете:

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

Когда вызов потока попадает в метод2 из метода1, он гарантирует, что он удерживает блокировку до this, которая уже будет, а затем она может пройти.

Когда поток попадает непосредственно в method1 или method2, он блокируется, пока не сможет получить блокировку (this), а затем он войдет.

Как отмечено Джеймсом Блэком в комментариях, вам нужно знать, что вы делаете внутри тела метода.

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

Вдруг это не потокобезопасно, потому что вы смотрите на ConcurrentModificationException в будущем, потому что method3 несинхронизирован и, следовательно, может быть вызван потоком A, а Thread B работает в method1.

Ответ 2

Является ли метод помеченным с синхронизированным вызовом другим безопасным потоком синхронизированного метода.

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

Однако мы можем быть уверены, что вызовы метода 1 и метода2 на одном и том же объекте, выполненные разными потоками, не будут выполняться одновременно. В зависимости от того, что делают эти методы, этого может быть достаточно, чтобы сказать, что класс является потокобезопасным по отношению к этим методам.

Ответ 3

На сайте Java Tutorials http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

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

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

Таким образом, Java гарантирует, что если 2 потока выполняют один и тот же метод, методы не будут выполняться одновременно, а один за другим.

Но вам нужно знать о проблеме Liveness, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

А также независимо от того, блокируете ли вы незаметно, в коде, который вы использовали this, который блокирует весь объект, если вашему объекту нужен только доступ к синхронизации для одной переменной, вы должны просто заблокировать эту переменную.