Ist es sicher, eine synchronisierte Methode von einer anderen synchronisierten Methode aus aufzurufen?

80

Wenn eine synchronisierte Methode eine andere synchronisierte Methode aufruft, ist sie threadsicher?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}
user705414
quelle
Würde dieser Artikel helfen zu antworten, oder wo sind Sie verwirrt? kalyanchakravarthy.net/?p=413
James Black
Ja, Sie müssen method2 nicht als synchronisiert markieren, vorausgesetzt, es wird nur im oben angegebenen Kontext aufgerufen.
Debracey
3
Ob es threadsicher ist, hängt auch davon ab, was bei beiden Methoden passiert. Wenn sie beispielsweise nicht threadsichere Listen aufrufen, sind sie möglicherweise nicht threadsicher, wenn ein anderer Thread diese Sammlung ändern könnte.
James Black
Als Antwort auf meine Vermutung lautet die eigentliche Frage: Ja, das synchronisierte Schlüsselwort verwendet rekursive Sperren. Sie können eine synchronisierte Methode sicher von einer anderen synchronisierten Methode aus aufrufen.
Brett Kail
Es ist schon eine Weile her, aber es ist immer noch der erste Treffer bei Google. Ja: Synchronisierte Blöcke / Methoden für dasselbe Objekt sind wiedereintrittsfähig. stackoverflow.com/questions/12219376/reentrant-synchronization
Szocske

Antworten:

102

Ja, wenn Sie Methoden als markieren synchronized, tun Sie dies wirklich:

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

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

Wenn der Thread-Aufruf von Methode1 in Methode2 gelangt, stellt er sicher, dass er die Sperre hält this, an der er sich bereits befindet, und kann dann durchlaufen.

Wenn der Thread direkt in Methode1 oder Methode2 gelangt, wird er blockiert, bis er die Sperre ( this) erhalten kann, und dann wird er eingegeben.

Wie von James Black in den Kommentaren bemerkt, müssen Sie sich darüber im Klaren sein, was Sie innerhalb des Methodenkörpers tun.

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

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

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

Plötzlich ist es nicht threadsicher, weil Sie ConcurrentModificationExceptionin Zukunft auf a schauen, weil method3es nicht synchronisiert ist und daher von Thread A aufgerufen werden kann, während Thread B arbeitet method1.

pickypg
quelle
Ich versuche eine Frage zu beantworten, die fast identisch mit der hier gestellten ist. Dies sind die 2 möglichen Antworten (die anderen 2 sagen, dass es nicht läuft), was ist richtig? C. Der Code wird ausgeführt, aber es besteht eine potenzielle Deadlock-Situation. D. Der Code wird einwandfrei ausgeführt, da Java eine Wiedereintrittssynchronisierung bietet, die es einem Thread ermöglicht, dieselbe Sperre mehr als einmal zu erhalten. ----- Ich vermute, es ist D, aber vielleicht Die mögliche Deadlock-Situation hängt vom Methodenkörper ab.
@ user3140993 Der Code hier hat keine Chance auf einen Deadlock. method3Zeigt unsichere Threading-Vorgänge an, aber Sie sind genau über die Wiedereintrittssynchronisation informiert.
Pickypg
6

Ist eine mit synchronisiertem Aufruf gekennzeichnete Methode ein weiterer synchronisierter Methoden-Thread sicher?

Im Allgemeinen ist es nicht möglich zu sagen. Dies hängt davon ab, was die Methoden tun und welche anderen Methoden in derselben und anderen Klassen.

Wir können jedoch sicher sein, dass Aufrufe von Methode1 und Methode2 für dasselbe Objekt, die von verschiedenen Threads ausgeführt werden, nicht gleichzeitig ausgeführt werden. Je nachdem, was die Methoden tun, kann dies ausreichen, um zu sagen, dass die Klasse in Bezug auf diese Methoden threadsicher ist.

Stephen C.
quelle
1

Von der Java Tutorials-Website http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

  1. Es ist nicht möglich, dass zwei Aufrufe synchronisierter Methoden für dasselbe Objekt verschachtelt werden. Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Ausführung aussetzen), bis der erste Thread mit dem Objekt fertig ist.

  2. Wenn eine synchronisierte Methode beendet wird, wird automatisch eine Vorher-Beziehung zu einem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt hergestellt. Dies garantiert, dass Änderungen am Status des Objekts für alle Threads sichtbar sind

Java stellt also sicher, dass, wenn zwei Threads dieselbe Methode ausführen, die Methoden nicht gleichzeitig, sondern nacheinander ausgeführt werden.

Sie müssen sich jedoch des Liveness-Problems bewusst sein: http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

Und auch , ob Sie uncessarily sind blockiert, weil im Code verwendet man diese , die das ganze Objekt sperrt, wenn das Objekt nur sync Zugriff auf eine Variable benötigt , sollten Sie nur diese Variable sperren.

Stephen Lee
quelle
@ Stephen Lee - Sie können eine Variable nicht sperren. Dann sagen Sie, synchronized (this.someVar)Sie schauen auf das Objekt, in dem sich die Referenz befindet someVar. Die Unterscheidung ist sehr wichtig.
Stephen C