web-dev-qa-db-de.com

Kommt es tatsächlich zu unerwünschten Aufweckungen in Java?

Verschiedene Fragen zum Thema Sperren und (fast) immer das Finden der 'Schleife wegen falschen Aufweckens'1 Ich frage mich, hat jemand eine solche Art von Aufwecken erlebt (vorausgesetzt, eine annehmbare Hardware-/Software-Umgebung).

Ich weiß, dass der Begriff "unecht" keinen offensichtlichen Grund bedeutet, aber was können die Gründe für ein solches Ereignis sein?

(1 Hinweis: Die Loop-Übung wird nicht in Frage gestellt.)

Edit: Eine Hilfsfrage (für diejenigen, die Codebeispiele mögen):

Wenn ich das folgende Programm habe und es ausführen möchte:

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 diesen await fälschlich aufzuwecken, ohne für immer auf ein zufälliges Ereignis zu warten?

192
akarnokd

Der Wikipedia Artikel über falsche Wakeups hat diesen Leckerbissen:

Die Funktion pthread_cond_wait() in Linux wird mithilfe des Systemaufrufs futex implementiert. Jeder blockierende Systemaufruf unter Linux kehrt abrupt mit EINTR zurück, wenn der Prozess ein Signal empfängt. ... pthread_cond_wait() kann das Warten nicht erneut starten, da in der kurzen Zeit, in der es außerhalb des Systemaufrufs futex war, ein wirkliches Aufwecken versäumt wurde. Diese Wettlaufsituation kann nur dadurch vermieden werden, dass der Anrufer eine Invariante prüft. Ein POSIX-Signal erzeugt daher ein falsches Aufwecken.

Summary: Wenn ein Linux-Prozess signalisiert wird, werden seine wartenden Threads jeweils mit einem Nice, hot falsches Aufwachen zufrieden gestellt.

Ich kaufe es. Diese Pille ist leichter zu schlucken als der oft vage Grund, der oft aus Gründen der Leistung angegeben wird.

192
John Kugelman

Ich habe ein Produktionssystem, das dieses Verhalten aufweist. Ein Thread wartet auf ein Signal, dass sich eine Nachricht in der Warteschlange befindet. In belebten Zeiten sind bis zu 20% der Aufweckungen falsch (dh wenn sie dort aufwachen) ist nichts in der Warteschlange) Dieser Thread ist der einzige Benutzer der Nachrichten. Er läuft auf einer Linux-SLES-10-Box mit 8 Prozessoren und ist mit GCC 4.1.2 .. erstellt. Die Nachrichten werden angezeigt von einer externen Quelle und werden asynchron verarbeitet, da es Probleme gibt, wenn mein System sie nicht schnell genug liest.

21
Mr.Dirty.Birdy

Zur Beantwortung der Frage im Titel - Ja! es passiert tatsächlich. Obwohl der Wiki-Artikel einiges über unechte Aufweckungen erwähnt, ist eine nette Erklärung für die gleiche, die ich gefunden habe, folgendes: 

Denken Sie einfach daran ... Wie bei jedem Code kann es beim Thread-Scheduler zu einem vorübergehenden Blackout kommen, wenn in der zugrunde liegenden Hardware/Software etwas Ungewöhnliches passiert. Natürlich sollte darauf geachtet werden, dass dies so selten wie möglich geschieht. Da es jedoch keine 100% robuste Software gibt, kann davon ausgegangen werden, dass dies der Fall sein kann, und sorgt für die ordnungsgemäße Wiederherstellung, falls der Scheduler dies feststellt (z durch Beobachtung fehlender Herzschläge).

Wie könnte sich der Scheduler nun erholen, wenn man bedenkt, dass es während des Blackouts einige Signale verpassen kann, die wartende Threads benachrichtigen sollen? Wenn der Scheduler nichts tut, werden die erwähnten "unglücklichen" Threads einfach hängen bleiben und warten - um dies zu vermeiden, sendet der Scheduler einfach ein Signal an alle wartenden Threads.

Dies macht es notwendig, einen "Vertrag" zu erstellen, dass der wartende Thread ohne Grund benachrichtigt werden kann. Um genau zu sein, würde es einen Grund geben - Scheduler-Blackout -, da Thread jedoch (aus gutem Grund) so konzipiert ist, dass er die internen Implementierungsdetails des Schedulers nicht kennt, ist es wahrscheinlich, dass dieser Grund besser als "falsch" dargestellt wird.

Ich las diese Antwort von Source und fand sie vernünftig genug. Lesen Sie auch

Unruhiges Aufwachen in Java und wie Sie sie vermeiden können

PS: Der obige Link führt zu meinem persönlichen Blog, der zusätzliche Informationen zu unechten Aufweckvorgängen enthält. 

13
Aniket Thakur

Cameron Purdy schrieb einen Blogeintrag vor einer Weile darüber, dass er von dem unechten Aufwachproblem betroffen wurde. Ja, es passiert

Ich vermute, es liegt in der Spezifikation (als eine Möglichkeit) aufgrund von Einschränkungen einiger Plattformen, auf denen Java bereitgestellt wird. obwohl ich falsch sein kann!

8
oxbow_lakes

Nur um dies hinzuzufügen. Ja, es passiert und ich habe drei Tage lang auf einem 24-Core-Rechner (JDK 6) nach der Ursache eines Multi-Threading-Problems gesucht. 4 von 10 Ausführungen erlebten das ohne Muster. Dies geschah nie auf 2 Kernen oder 8 Kernen.

Studierte etwas Online-Material und dies ist kein Java-Problem, sondern ein allgemeines seltenes, aber erwartetes Verhalten.

8
ReneS

https://stackoverflow.com/a/1461956/14731 enthält eine ausgezeichnete Erklärung dafür, warum Sie gegen unbeabsichtigtes Aufwecken schützen müssen, auch wenn das zugrunde liegende Betriebssystem diese nicht auslöst. Es ist interessant festzustellen, dass diese Erklärung für mehrere Programmiersprachen gilt, einschließlich Java.

0
Gili