Wer ruft die Java Thread Interrupt () Methode auf, wenn ich es nicht bin?


86

Ich habe Java Concurrency in der Praxis gelesen und erneut gelesen, ich habe hier mehrere Themen zu diesem Thema gelesen, ich habe den IBM-Artikel Umgang mit InterruptedException gelesen und dennoch gibt es etwas, das ich einfach nicht verstehe und das meiner Meinung nach gebrochen werden kann in zwei Fragen:

  1. Was kann eine InterruptedException auslösen, wenn ich niemals andere Threads selbst unterbreche ?

  2. Wenn ich niemals selbst andere Threads mit Interrupt () unterbreche ( sagen wir, weil ich andere Mittel verwende, um meine Arbeitsthreads abzubrechen, wie Giftpillen und während (! Abgebrochene) Schleife [wie beide in JCIP erklärt]), was? bedeutet dann eine InterruptedException ? Was soll ich tun, wenn ich einen fange? App herunterfahren?

Antworten:


50

Der Thread-Interrupt-Mechanismus ist der bevorzugte Weg, um einen (kooperierenden) Thread dazu zu bringen, auf eine Anfrage zu antworten, um zu stoppen, was er tut. Jeder Thread (einschließlich des Threads selbst, denke ich) könnte interrupt()einen Thread aufrufen .

In der Praxis umfassen die normalen Anwendungsfälle interrupt()eine Art Framework oder Manager, der einem Arbeitsthread sagt, er solle aufhören, was er tut. Wenn der Worker-Thread "Interrupt-fähig" ist, wird er feststellen, dass er durch eine Ausnahme oder durch regelmäßige Überprüfung seines unterbrochenen Flags unterbrochen wurde. Wenn ein gut erzogener Thread bemerkt, dass er unterbrochen wurde, gibt er auf, was er tut, und beendet sich selbst.

Unter der Annahme des obigen Anwendungsfalls wird Ihr Code wahrscheinlich unterbrochen, wenn er in einem Java-Framework oder in einem Arbeitsthread ausgeführt wird. Und wenn es unterbrochen wird, sollte Ihr Code aufgeben, was er tut, und sich mit den am besten geeigneten Mitteln selbst beenden. Abhängig davon, wie Ihr Code aufgerufen wurde, kann dies durch Zurückgeben oder durch Auslösen einer geeigneten Ausnahme erfolgen. Aber es sollte wohl nicht anrufen System.exit(). (Ihre Anwendung weiß nicht unbedingt, warum sie unterbrochen wurde, und sie weiß sicherlich nicht, ob andere Threads vom Framework unterbrochen werden müssen.)

Wenn Ihr Code jedoch nicht für die Ausführung unter einem bestimmten Framework ausgelegt ist, können Sie argumentieren, dass dies InterruptedExceptioneine unerwartete Ausnahme ist. dh ein Fehler. In diesem Fall sollten Sie die Ausnahme wie andere Fehler behandeln. Binden Sie es beispielsweise in eine nicht aktivierte Ausnahme ein und fangen Sie es an derselben Stelle ab und protokollieren Sie es, an der Sie sich mit anderen unerwarteten nicht aktivierten Ausnahmen befassen. (Alternativ kann Ihre Anwendung den Interrupt einfach ignorieren und das tun, was sie getan hat.)


1) Was kann eine InterruptedException auslösen, wenn ich niemals andere Threads selbst unterbreche?

Ein Beispiel ist, wenn Ihre RunnableObjekte mit einem ausgeführt werden ExecutorServiceund shutdownNow()im Dienst aufgerufen werden. Und theoretisch könnte jeder Thread-Pool oder jedes Thread-Management-Framework eines Drittanbieters legitimerweise so etwas tun.

2) Wenn ich niemals selbst andere Threads mit Interrupt () unterbreche ... was bedeutet ein InterruptedExceptiondann? Was soll ich tun, wenn ich einen fange? App herunterfahren?

Sie müssen die Codebasis analysieren, um herauszufinden, was die interrupt()Anrufe tätigt und warum. Sobald Sie das herausgefunden haben, können Sie herausfinden, was >> Ihr << Teil der App tun muss.

Bis Sie wissen, warum InterruptedExceptiongeworfen wird, würde ich empfehlen, es als einen schweren Fehler zu behandeln; Drucken Sie beispielsweise einen Stacktrace in die Protokolldatei und fahren Sie die App herunter. (Natürlich ist das nicht immer die richtige Antwort ... aber der Punkt ist, dass dies "ein Fehler" ist und der Entwickler / Betreuer darauf aufmerksam gemacht werden muss.)

3) Wie finde ich heraus, wer / was anruft interrupt()?

Darauf gibt es keine gute Antwort. Das Beste, was ich vorschlagen kann, ist, einen Haltepunkt auf dem festzulegen Thread.interrupt()und den Aufrufstapel zu betrachten.


12

Wenn Sie Ihren Code in andere Bibliotheken integrieren möchten, können diese interrupt()Ihren Code aufrufen . Wenn Sie sich beispielsweise in Zukunft dafür entscheiden, Ihren Code in einem ExecutorService auszuführen , kann dies ein Herunterfahren über erzwingen interrupt().

Um es kurz zu machen, ich würde nicht nur überlegen, wo Ihr Code jetzt ausgeführt wird , sondern auch, in welchem ​​Kontext er in Zukunft ausgeführt werden könnte. zB wirst du es in eine Bibliothek stellen? Ein Container ? Wie werden andere Leute es benutzen? Wirst du es wiederverwenden?


Ich dachte nur shutdownNow ruft die Interrupt () Methode auf. Gilt das auch für das Herunterfahren?
Harinder

9

Wie andere bereits betont haben, wird das Unterbrechen eines Threads (tatsächlich das Unterbrechen eines blockierenden Anrufs) normalerweise zum sauberen Beenden oder zum Abbrechen einer laufenden Aktivität verwendet.

Sie sollten einen InterruptedExceptionallein jedoch nicht als "Beenden-Befehl" behandeln. Stattdessen sollten Sie sich Interrupts als Mittel vorstellen, um den laufenden Status von Threads zu steuern, ähnlich wie dies der Object.notify()Fall ist. Auf die gleiche Weise, wie Sie den aktuellen Status nach dem Aufwachen von einem Anruf an überprüfen würden Object.wait()(Sie gehen nicht davon aus, dass das Aufwecken bedeutet, dass Ihre Wartebedingung erfüllt ist), sollten Sie nach einem Anstoß mit einem Interrupt überprüfen, warum Sie unterbrochen wurden . Es gibt normalerweise einen Weg, dies zu tun. Hat zum Beispiel java.util.concurrent.FutureTaskeine isCancelled()Methode.

Codebeispiel:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}

3

Das Problem mit der Frage ist "Ich". "Ich" bezieht sich normalerweise auf eine einzelne Instanz einer Klasse. Ich meine damit, dass ein bestimmtes Stück Code (Klasse) auf niedriger Ebene nicht auf der Implementierung des gesamten Systems beruhen sollte. Allerdings müssen Sie einige "architektonische" Entscheidungen treffen (z. B. auf welcher Plattform ausgeführt werden soll).

Mögliche unerwartete Interrupts, die von der JRE kommen, sind abgebrochene Aufgaben in java.util.concurrentund das Herunterfahren von Applets.

Die Behandlung von Thread-Interrupts wird normalerweise falsch geschrieben. Daher schlage ich die architektonische Entscheidung vor, nach Möglichkeit keine Interrupts zu verursachen. Code-Handling-Interrupts sollten jedoch immer korrekt geschrieben werden. Interrupts können jetzt nicht aus der Plattform entfernt werden.


Hallo Tom, ich erinnere mich an deinen Namen von cljp;) Nun, genau: Ich musste nie unterbrechen () selbst ... Es sei denn, ich fange eine InterruptedException und muss den unterbrochenen Status erneut bestätigen, aber dies ist immer noch nicht 100% verständlich für mich. Ich bin neu hier und überrascht von der Anzahl der positiven Stimmen und Antworten / Kommentare (sowohl die richtigen als auch die falschen): Offensichtlich ist es ein Thema, das nicht trivial oder zumindest normalerweise nicht gut erklärt ist. Das heißt, dank all der Beiträge bekomme ich ein klareres Bild davon, was los ist :)
SyntaxT3rr0r

2

Sie können dies lernen, indem Sie eine eigene Thread-Klasse (Erweiterung java.lang.Thread) und eine überschreibende interrupt()Methode erstellen , in der Sie den Stacktrace beispielsweise in ein String-Feld aufzeichnen und dann an super.interrupt () übertragen.

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}

1

Wie bereits erwähnt, kann eine andere Bibliothek Ihre Threads unterbrechen. Auch wenn die Bibliothek keinen expliziten Zugriff auf die Threads aus Ihrem Code hat, können sie die Liste der ausgeführten Threads abrufen und sie auf diese Weise mit der folgenden Methode unterbrechen .


1

Ich glaube, ich verstehe, warum Sie wegen der Unterbrechung etwas verwirrt sind. Bitte beachten Sie meine Antworten in der Zeile:

Was kann eine InterruptedException auslösen, wenn ich niemals andere Threads selbst unterbreche ?

Erstens können Sie andere Threads unterbrechen. Ich weiß, dass in JCiP erwähnt wird, dass Sie niemals Threads unterbrechen sollten, die Sie nicht besitzen. Diese Aussage muss jedoch richtig verstanden werden. Dies bedeutet, dass Ihr Code, der möglicherweise in einem beliebigen Thread ausgeführt wird, keine Unterbrechung verarbeiten sollte, da er nicht der Eigentümer des Threads ist und keine Ahnung von seiner Unterbrechungsrichtlinie hat. Sie können also eine Unterbrechung für andere Threads anfordern, aber den Eigentümer die Unterbrechungsaktion ausführen lassen. Darin ist die Unterbrechungsrichtlinie enthalten, nicht Ihr Aufgabencode. Sei zumindest höflich, das Unterbrechungsflag zu setzen!

Es gibt viele Möglichkeiten, warum es immer noch zu Unterbrechungen, Zeitüberschreitungen, JVM-Unterbrechungen usw. kommen kann.

Wenn ich niemals andere Threads selbst mit Interrupt () unterbreche (sagen wir, weil ich andere Mittel verwende, um meine Arbeitsthreads abzubrechen, wie Giftpillen und während (! Abgebrochene) Stilschleife [wie beide in JCIP erklärt]), was bedeutet dann eine InterruptedException? Was soll ich tun, wenn ich einen fange? App herunterfahren?

Sie müssen hier sehr vorsichtig sein; Wenn Sie den Thread besitzen, der InterruptedException (IE) ausgelöst hat, wissen Sie, was zu tun ist, wenn Sie ihn abfangen. Sagen Sie, Sie können Ihre App / Ihren Dienst herunterfahren oder diesen getöteten Thread durch einen neuen ersetzen! Wenn Sie den Thread jedoch nicht besitzen, werfen Sie ihn beim Abfangen des IE entweder höher im Aufrufstapel oder nachdem Sie etwas getan haben (möglicherweise protokolliert), setzen Sie den unterbrochenen Status zurück, damit der Code, dem dieser Thread gehört, wenn die Steuerung ihn erreicht, dies kann Erfahren Sie, dass der Thread unterbrochen wurde, und ergreifen Sie daher die erforderlichen Aktionen, da nur er die Unterbrechungsrichtlinie kennt.

Hoffe das hat geholfen.


0

Das InterruptedExceptionbesagt , dass eine Routine kann unterbrochen werden, aber nicht unbedingt , dass es sein wird.

Wenn Sie den Interrupt nicht erwarten, sollten Sie ihn wie jede andere unerwartete Ausnahme behandeln. Wenn es sich in einem kritischen Bereich befindet, in dem eine unerwartete Ausnahme abscheuliche Folgen haben kann, ist es möglicherweise am besten, Ressourcen zu bereinigen und ordnungsgemäß herunterzufahren (da das Abrufen der Interrupts signalisiert, dass Ihre ausgereifte Anwendung verwendet wird, die nicht auf Interrupts angewiesen ist in gewisser Weise war es nicht entworfen, und so muss etwas falsch sein). Wenn der betreffende Code nicht kritisch oder trivial ist, können Sie den Interrupt ignorieren (oder protokollieren) und weitermachen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.