Sowohl die Sicherheit als auch die Verfügbarkeit sind bei der Verwendung des Wartungs-/Benachrichtigungsmechanismus von Bedeutung. Die Sicherheitseigenschaft erfordert, dass alle Objekte in einer Multithread-Umgebung konsistente Zustände beibehalten. Die Liveness-Eigenschaft erfordert, dass jeder Vorgang oder Methodenaufruf ohne Unterbrechung ausgeführt wird.
Vitalitäts zu gewährleisten, Programme müssen die while-Schleife Zustand testen, bevor die Methode wait() aufgerufen wird. Dieser frühe Test überprüft, ob ein anderer Thread das Bedingungsprädikat bereits erfüllt und eine Benachrichtigung gesendet hat. Das Aufrufen der Methode wait() nach dem Senden der Benachrichtigung führt zu einer unbestimmten Blockierung.
Um die Sicherheit zu gewährleisten, Programme müssen die while-Schleife Zustand getestet werden, danach von der Methode wait() zurückkehrt. Obwohl wait() soll auf unbestimmte Zeit blockieren, bis eine Meldung empfangen wird, muß es immer noch in einer Schleife eingeschlossen werden, um die folgenden Schwachstellen zu verhindern:
Gewinde in der Mitte: Ein dritte Thread die Sperre an dem gemeinsam genutzten erwerben Objekt während des Intervalls zwischen einer gesendeten Benachrichtigung und der Wiederaufnahme der Ausführung des empfangenden Threads. Dieser dritte Thread kann den Status des Objekts ändern und es inkonsistent lassen. Dies ist eine Race-Bedingung für den Zeitpunkt der Überprüfung, Nutzungszeit (TOCTOU).
Bösartige Benachrichtigung: Eine zufällige oder bösartige Benachrichtigung kann empfangen werden, wenn das Prädikat der Bedingung falsch ist. Eine solche Benachrichtigung würde die Methode wait() abbrechen.
Fehlgeleitete Benachrichtigung: Die Reihenfolge, in der Threads nach Empfang eines notifyAll() - Signals ausgeführt werden, ist nicht angegeben. Folglich kann ein nicht verwandter Thread mit der Ausführung beginnen und feststellen, dass sein Bedingungsprädikat erfüllt ist. Folglich könnte es die Ausführung fortsetzen, obwohl es erforderlich ist, ruhend zu bleiben.
Unechte Wakeups: Bestimmte Java Virtual Machine (JVM) Implementierungen sind anfällig für störende Wakeups, die auch ohne Benachrichtigung Aufwachen in wartenden Threads führen.
Aus diesen Gründen müssen Programme das Bedingungsprädikat überprüfen, nachdem die wait() -Methode zurückgegeben wurde. Eine while-Schleife ist die beste Wahl, um das Bedingungsprädikat vor und nach dem Aufruf von wait() zu überprüfen.
In ähnlicher Weise muss die await() - Methode der Condition-Schnittstelle auch innerhalb einer Schleife aufgerufen werden. Gemäß der Java-API-Schnittstelle Zustand
Wenn auf eine Bedingung wartet, wird eine „unechte Wakeup“ gestattet auftreten, in der Regel als Zugeständnis an die zugrunde liegende Plattform Semantik. Dies hat wenig praktische Auswirkungen auf die meisten Anwendungen Programme als eine Bedingung sollte immer in einer Schleife gewartet werden, Testen der Staat Prädikat, auf das gewartet wird. Eine Implementierung ist frei, um die Möglichkeit von unechten Wakeups zu entfernen, aber es wird empfohlen, dass Anwendungsprogrammierer immer davon ausgehen, dass sie auftreten können und so immer in einer Schleife warten.
Neuer Code sollte die java.util.concurrent.locks-Nebenläufigkeitsdienstprogramme anstelle des Wartungs-/Benachrichtigungsmechanismus verwenden. Legacycode, der den anderen Anforderungen dieser Regel entspricht, darf jedoch vom Wartungs-/Benachrichtigungsmechanismus abhängen.
Nicht kompatibel Codebeispiel Dieses noncompliant Codebeispiel ruft die Methode wait() in einem traditionellen, wenn Block und nicht die Nachbedingung zu überprüfen, nachdem die Benachrichtigung empfangen wird. Wenn die Benachrichtigung zufällig oder bösartig war, konnte der Thread vorzeitig aufwachen.
synchronized (object) {
if (<condition does not hold>) {
object.wait();
}
// Proceed when condition holds
}
konforme Lösung Diese konforme Lösung ruft die wait() Methode aus einer while-Schleife um den Zustand zu prüfen, sowohl vor als auch nach dem Anruf warten():
synchronized (object) {
while (<condition does not hold>) {
object.wait();
}
// Proceed when condition holds
}
Invocations von Die Methode java.util.concurrent.locks.Condition.await() muss ebenfalls in eine ähnliche Schleife eingeschlossen sein.
Hinweis: Oracle-Dokumentation nennt dieses Idiom einen "geschützten Block" https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html –