Jeśli metoda synchroniczna wywołuje inną metodę zsynchronizowaną, czy jest bezpieczna wątkowo?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
java
thread-safety
user705414
źródło
źródło
Odpowiedzi:
Tak, kiedy oznaczysz metody jako
synchronized
, to naprawdę robisz to:void method1() { synchronized (this) { method2() } } void method2() { synchronized (this) { } }
Kiedy wywołanie wątku dostaje się do metody method2 z metody method1, wtedy upewnia się, że utrzymuje blokadę, do
this
której już będzie, a następnie może przejść.Gdy wątek przechodzi bezpośrednio do metody method1 lub method2, będzie blokować, dopóki nie będzie mógł uzyskać funkcji lock (
this
), a następnie wejdzie.Jak zauważył James Black w komentarzach, musisz być świadomy tego, co robisz w treści metody.
private final List<T> data = new ArrayList<T>(); public synchronized void method1() { for (T item : data) { // .. } } public void method3() { data.clear(); }
Nagle nie jest to bezpieczne wątkowo, ponieważ patrzysz na a
ConcurrentModificationException
w przyszłości, ponieważmethod3
jest niezsynchronizowany, a zatem może zostać wywołany przez wątek A, gdy wątek B pracujemethod1
.źródło
method3
pokazuje niebezpieczne operacje na wątkach, ale jesteś na bieżąco z synchronizacją ponownie.Ogólnie rzecz biorąc, nie można tego powiedzieć. Zależy to od tego, co robią metody i jakie są inne metody w tej samej i innych klasach.
Możemy jednak być pewni, że wywołania metody method1 i method2 na tym samym obiekcie przez różne wątki nie będą wykonywane jednocześnie. W zależności od tego, co robią metody, może to wystarczyć, aby stwierdzić, że klasa jest bezpieczna wątkowo w odniesieniu do tych metod.
źródło
Z witryny samouczków Java http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Nie ma możliwości przeplotu dwóch wywołań metod zsynchronizowanych na tym samym obiekcie. Gdy jeden wątek wykonuje zsynchronizowaną metodę dla obiektu, wszystkie inne wątki, które wywołują zsynchronizowane metody dla tego samego bloku obiektu (wstrzymują wykonywanie), dopóki pierwszy wątek nie zostanie zakończony z obiektem.
gdy metoda synchroniczna kończy działanie, automatycznie ustanawia relację zdarzenie przed każdym kolejnym wywołaniem metody synchronicznej dla tego samego obiektu. Gwarantuje to, że zmiany stanu obiektu są widoczne dla wszystkich wątków
Tak więc Java zapewni, że jeśli 2 wątki wykonują tę samą metodę, metody nie będą wykonywane jednocześnie, ale jedna po drugiej.
Ale musisz zdawać sobie sprawę z problemu Liveness, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
A także, czy blokujesz bez powodzenia, ponieważ w kodzie, którego użyłeś tego , który blokuje cały obiekt, jeśli twój obiekt potrzebuje dostępu synchronizacyjnego tylko do jednej zmiennej, powinieneś po prostu zablokować tę zmienną.
źródło
synchronized (this.someVar)
że patrzysz na obiekt, którego odniesienie jest zachowanesomeVar
. To rozróżnienie jest bardzo ważne.