Sehen verschiedene Verriegelungs Zusammenhang Frage und (fast) immer die ‚Schleife wegen falschen Wakeups‘ zu finden Begriffe 1 I Wunder, hat jemand erlebt eine solche Art eines Wake - up (eine anständige Hardware / Software - Umgebung zum Beispiel angenommen wird )?
Ich weiß, dass der Begriff "falsch" keinen offensichtlichen Grund bedeutet, aber was können die Gründe für eine solche Art von Ereignis sein?
( 1 Hinweis: Ich stelle die Schleifenpraxis nicht in Frage.)
Bearbeiten: Eine Hilfsfrage (für diejenigen, die Codebeispiele mögen):
Wenn ich das folgende Programm habe und es ausführe:
public class Spurious {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
Was kann ich tun, um dies await
falsch aufzuwecken , ohne ewig auf ein zufälliges Ereignis zu warten?
java
multithreading
locking
spurious-wakeup
akarnokd
quelle
quelle
pthread_cond_wait()
die eigentliche Frage verwenden, lautet die eigentliche Frage: "Warum hat pthread_cond_wait falsche Aufweckvorgänge?" .Antworten:
Der Wikipedia- Artikel über falsche Weckrufe hat diesen Leckerbissen:
Zusammenfassung : Wenn ein Linux-Prozess signalisiert wird, genießen seine wartenden Threads jeweils ein schönes, heißes, falsches Aufwecken .
Ich kaufe es. Das ist eine Pille, die leichter zu schlucken ist als der oft vage, oft angegebene Grund für die Leistung.
quelle
futex()
Aufruf wird zurückgegebenEINTR
, aber dieser Rückgabewert wird nicht auf die nächste Ebene übertragen. Der pthread-Aufrufer muss daher nach einer Invariante suchen. Was sie sagen ist, dass Sie bei derpthread_cond_wait()
Rückgabe Ihre Schleifenbedingung (unveränderlich) erneut überprüfen müssen, da das Warten möglicherweise falsch geweckt wurde. Das Empfangen eines Signals während eines Systemaufrufs ist eine mögliche Ursache, aber nicht die einzige.pthread
könnte die Bibliothek ihre eigene Invariante und ihre eigene Überprüfungslogik bereitstellen, um falsche Aufweckvorgänge zu vermeiden, anstatt diese Verantwortung auf den Benutzer zu übertragen. Dies hätte (vermutlich) die behaupteten Auswirkungen auf die Leistung.Ich habe ein Produktionssystem, das dieses Verhalten zeigt. Ein Thread wartet auf ein Signal, dass sich eine Nachricht in der Warteschlange befindet. In Stoßzeiten sind bis zu 20% der Weckvorgänge falsch (dh wenn sie aufwachen, befindet sich nichts in der Warteschlange). Dieser Thread ist der einzige Verbraucher der Nachrichten. Es läuft auf einer Linux SLES-10 8-Prozessor-Box und basiert auf GCC 4.1.2. Die Nachrichten stammen von einer externen Quelle und werden asynchron verarbeitet, da Probleme auftreten, wenn mein System sie nicht schnell genug liest.
quelle
Um die Frage im Titel zu beantworten - Ja! Es passiert. Obwohl der Wiki-Artikel viel über falsche Weckrufe erwähnt, ist eine nette Erklärung für dasselbe, auf das ich gestoßen bin, wie folgt:
Ich habe diese Antwort von Source gelesen und fand sie vernünftig genug. Lesen Sie auch
Falsche Weckrufe in Java und wie man sie vermeidet .
PS: Der obige Link führt zu meinem persönlichen Blog, der zusätzliche Details zu falschen Weckvorgängen enthält.
quelle
Cameron Purdy hat vor einiger Zeit einen Blog-Beitrag darüber geschrieben, wie er von dem falschen Weckproblem getroffen wird. Also ja, es passiert
Ich vermute, es ist in der Spezifikation (als eine Möglichkeit) wegen der Einschränkungen einiger der Plattformen, auf denen Java bereitgestellt wird? obwohl ich mich vielleicht irre!
quelle
Nur um das hinzuzufügen. Ja, es passiert und ich habe drei Tage lang auf einem 24-Kern-Computer (JDK 6) nach der Ursache eines Multithreading-Problems gesucht. 4 von 10 Hinrichtungen erlebten dies ohne Muster. Dies geschah nie auf 2 Kernen oder 8 Kernen.
Studierte Online-Material und dies ist kein Java-Problem, sondern ein allgemein seltenes, aber erwartetes Verhalten.
quelle
https://stackoverflow.com/a/1461956/14731 enthält eine hervorragende Erklärung, warum Sie sich vor falschen Aufwecken schützen müssen, auch wenn das zugrunde liegende Betriebssystem sie nicht auslöst. Es ist interessant festzustellen, dass diese Erklärung für mehrere Programmiersprachen gilt, einschließlich Java.
quelle
Beantwortung der Frage des OP
, Keine jede falsche Wakeup könnte diese Erwartung Thread aufwachen!
Unabhängig davon , ob falsche Wakeups kann oder nicht auf einer bestimmten Plattform, in einem Fall , der OPs passieren kann Snippet es positiv ist unmöglich für
Condition.await()
zurückzukehren und die Linie zu sehen „Unechte Wakeup!“ im Ausgabestream.Es sei denn, Sie verwenden eine sehr exotische Java-Klassenbibliothek
Dies liegt daran , Standard, OpenJDK ‚s
ReentrantLock
‘ s MethodenewCondition()
kehrt dieAbstractQueuedSynchronizer
‚s Umsetzung derCondition
Schnittstelle, verschachteltConditionObject
(übrigens ist es die einzige Implementierung derCondition
Schnittstelle in dieser Klassenbibliothek) und dieConditionObject
‘ s Methodeawait()
selbst überprüft , ob die Bedingung nicht hält und kein falsches Aufwecken könnte diese Methode zwingen, fälschlicherweise zurückzukehren.Übrigens können Sie es selbst überprüfen, da es ziemlich einfach ist, ein falsches Aufwecken zu emulieren, sobald die
AbstractQueuedSynchronizer
basierte Implementierung beteiligt ist.AbstractQueuedSynchronizer
verwendet Low-LevelLockSupport
‚spark
undunpark
Methoden, und wenn Sie invokeLockSupport.unpark
auf einem Thread wartet aufCondition
, kann diese Aktion nicht von einem falschen Wakeup unterschieden werden.Das OP-Snippet leicht umgestalten,
Unabhängig davon, wie sehr der Unparking-Thread (Hauptthread) versuchen würde, den wartenden Thread zu aktivieren, wird die
Condition.await()
Methode in diesem Fall niemals zurückkehren.Die falschen Aufweckmethoden für
Condition
die erwarteten Methoden werden im Javadoc derCondition
Schnittstelle erläutert . Obwohl es das sagt,und das
aber es fügt das später hinzu
und
AbstractQueuedSynchronizer
die Implementierung derCondition
Schnittstelle macht genau das - beseitigt jede Möglichkeit von falschen Aufwecken .Dies gilt sicherlich auch für
ConditionObject
die erwarteten Methoden anderer .Die Schlussfolgerung lautet also:
Wir sollten immer
Condition.await
in der Schleife aufrufen und prüfen, ob die Bedingung nicht erfüllt ist, aber mit Standard, OpenJDK, Java Class Library kann dies niemals passieren . Es sei denn, Sie verwenden erneut eine sehr ungewöhnliche Java-Klassenbibliothek (was sehr, sehr ungewöhnlich sein muss, da andere bekannte Nicht-OpenJDK-Java-Klassenbibliotheken, derzeit fast ausgestorbene GNU-Klassenpfade und Apache Harmony , mit der Standardimplementierung derCondition
Schnittstelle identisch zu sein scheinen ).quelle