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


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

void synchronized method1() {
     method2()
}

void synchronized method2() {
}
3 72

3 ответа:

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

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

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

когда вызов потока попадает в method2 из method1, он гарантирует, что он удерживает блокировку в 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, пока поток B работает в method1.

- Это метод, отмеченный синхронизированным вызовом другого синхронизированного метода потокобезопасности.

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

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

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

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

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

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

но вы должны быть в курсе о проблеме живучести, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

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