Безопасно ли вызывать синхронизированный метод из другого синхронизированного метода? - PullRequest
76 голосов
/ 27 апреля 2011

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

void synchronized method1() {
     method2()
}

void synchronized method2() {
}

Ответы [ 3 ]

97 голосов
/ 27 апреля 2011

Да, когда вы помечаете методы как 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.

5 голосов
/ 27 апреля 2011

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

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

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

1 голос
/ 27 апреля 2011

с сайта 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...