it-swarm.com.de

Behandlung von InterruptedException in Java

Was ist der Unterschied zwischen den folgenden Methoden zur Behandlung von InterruptedException? Wie geht das am besten?

try{
 //...
} catch(InterruptedException e) { 
   Thread.currentThread().interrupt(); 
}

OR

try{
 //...
} catch(InterruptedException e) {
   throw new RuntimeException(e);
}

EDIT: Ich möchte auch wissen, in welchen Szenarien diese beiden verwendet werden.

269
devnull

Was ist der Unterschied zwischen den folgenden Methoden zur Behandlung von InterruptedException? Wie geht das am besten?

Sie sind wahrscheinlich gekommen, um diese Frage zu stellen, weil Sie eine Methode aufgerufen haben, die InterruptedException auslöst.

Zunächst sollten Sie throws InterruptedException Als das sehen, was es ist: Ein Teil der Methodensignatur und ein mögliches Ergebnis des Aufrufs der Methode, die Sie aufrufen. Beginnen Sie also damit, dass ein InterruptedException ein vollkommen gültiges Ergebnis des Methodenaufrufs ist.

Nun, wenn die Methode, die Sie aufrufen, eine solche Ausnahme auslöst, was sollte die Methode your tun? Sie können die Antwort herausfinden, indem Sie über Folgendes nachdenken:

Ist es sinnvoll, wenn die Methode you einen InterruptedException wirft? Anders ausgedrückt, ist ein InterruptedException ein vernünftiges Ergebnis beim Aufrufen der your -Methode?

  • Wenn yes , dann sollte throws InterruptedException Teil der your Methodensignatur sein, und Sie sollten das zulassen ausnahmebedingung verbreiten (dh überhaupt nicht abfangen).

    Beispiel : Ihre Methode wartet auf einen Wert aus dem Netzwerk, um die Berechnung abzuschließen und ein Ergebnis zurückzugeben. Wenn der blockierende Netzwerkaufruf einen InterruptedException auslöst, kann Ihre Methode die Berechnung nicht auf normale Weise beenden. Sie lassen das InterruptedException sich ausbreiten.

    int computeSum(Server server) throws InterruptedException {
        // Any InterruptedException thrown below is propagated
        int a = server.getValueA();
        int b = server.getValueB();
        return a + b;
    }
    
  • Wenn no , dann sollten Sie Ihre Methode nicht mit throws InterruptedException Deklarieren und Sie sollten (müssen!) Die Ausnahme abfangen. Nun sind in dieser Situation zwei Dinge zu beachten:

    1. Jemand hat Ihren Thread unterbrochen. Diese Person ist wahrscheinlich bestrebt, den Vorgang abzubrechen, das Programm ordnungsgemäß zu beenden oder was auch immer. Sie sollten höflich zu jemandem sein und ohne weiteres von Ihrer Methode zurückkehren.

    2. Auch wenn die Methode your im Falle eines InterruptedException einen vernünftigen Rückgabewert erzeugen kann, kann die Tatsache, dass der Thread unterbrochen wurde, dennoch von Bedeutung sein. Insbesondere der Code, der Ihre Methode aufruft, ist möglicherweise daran interessiert, ob während der Ausführung Ihrer Methode eine Unterbrechung aufgetreten ist. Sie sollten daher protokollieren, dass eine Unterbrechung stattgefunden hat, indem Sie das Flag "Unterbrochen" setzen: Thread.currentThread().interrupt()

    Beispiel : Der Benutzer hat gebeten, eine Summe von zwei Werten auszudrucken. Das Drucken von "Failed to compute sum" Ist zulässig, wenn die Summe nicht berechnet werden kann (und viel besser, als das Programm aufgrund eines InterruptedException mit einem Stack-Trace abstürzen zu lassen). Mit anderen Worten, es ist nicht sinnvoll, diese Methode mit throws InterruptedException Zu deklarieren.

    void printSum(Server server) {
         try {
             int sum = computeSum(server);
             System.out.println("Sum: " + sum);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();  // set interrupt flag
             System.out.println("Failed to compute sum");
         }
    }
    

Inzwischen sollte klar sein, dass es eine schlechte Idee ist, nur throw new RuntimeException(e) zu tun. Es ist nicht sehr höflich gegenüber dem Anrufer. Sie könnten eine neue Laufzeitausnahme erfinden, aber die Grundursache (jemand möchte, dass der Thread die Ausführung stoppt) könnte verloren gehen.

Andere Beispiele:

Runnable implementieren : Wie Sie vielleicht festgestellt haben, erlaubt die Signatur von Runnable.run Nicht, InterruptedExceptions. Nun, Sie hat sich bei der Implementierung von Runnable angemeldet, was bedeutet, dass Sie sich angemeldet hat, um mit möglichen InterruptedExceptions umzugehen. Wählen Sie entweder eine andere Schnittstelle aus, z. B. Callable , oder befolgen Sie den obigen zweiten Ansatz.

Aufruf von Thread.sleep: Sie versuchen, eine Datei zu lesen, und die Spezifikation besagt, dass Sie es 10 Mal mit 1 Sekunde dazwischen versuchen sollten. Sie rufen Thread.sleep(1000) auf. Sie müssen sich also mit InterruptedException befassen. Für eine Methode wie tryToReadFile ist es vollkommen sinnvoll zu sagen: "Wenn ich unterbrochen werde, kann ich meine Aktion zum Lesen der Datei nicht abschließen". Mit anderen Worten, es ist absolut sinnvoll, wenn die Methode InterruptedExceptions wirft.

String tryToReadFile(File f) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        if (f.exists())
            return readFile(f);
        Thread.sleep(1000);
    }
    return null;
}

Dieser Beitrag wurde als Artikel hier umgeschrieben.

383
aioobe

Zufällig habe ich heute Morgen auf dem Weg zur Arbeit in Java Concurrency In Practice von Brian Goetz darüber gelesen. Grundsätzlich sagt er, Sie sollten eines von zwei Dingen tun

  1. Veröffentlichen Sie das InterruptedException - Deklarieren Sie Ihre Methode, um das aktivierte InterruptedException zu werfen, damit Ihr Anrufer damit umgehen muss.

  2. Wiederherstellen des Interrupts - Manchmal können Sie InterruptedException nicht werfen. In diesen Fällen sollten Sie das InterruptedException abfangen und den Interrupt-Status wiederherstellen, indem Sie die interrupt() -Methode für das currentThread aufrufen, damit der Code weiter oben im Aufruf-Stack erkennt, dass ein Interrupt vorliegt wurde ausgestellt.

87
mR_fr0g

Was versuchst du zu machen?

Das InterruptedException wird ausgelöst, wenn ein Thread wartet oder schläft und ein anderer Thread ihn mit der interrupt -Methode in der Klasse Thread unterbricht. Wenn Sie diese Ausnahme abfangen, bedeutet dies, dass der Thread unterbrochen wurde. Normalerweise macht es keinen Sinn, Thread.currentThread().interrupt(); erneut aufzurufen, es sei denn, Sie möchten den Status des Threads "unterbrochen" von einer anderen Stelle aus überprüfen.

In Bezug auf Ihre andere Option, ein RuntimeException zu werfen, scheint es nicht sehr klug zu sein (wer fängt das auf? Wie wird es gehandhabt?), Aber es ist schwierig, ohne zusätzliche Informationen mehr zu sagen.

17
Grodriguez

Für mich ist das Wichtigste dabei: Eine InterruptedException ist nichts, was schief geht. Es ist der Thread, der tut, was Sie ihm gesagt haben. Daher ist ein erneutes Auslösen in einer RuntimeException ohne Sinn.

In vielen Fällen ist es sinnvoll, eine in eine RuntimeException eingeschlossene Ausnahme erneut auszulösen, wenn Sie sagen, dass ich nicht weiß, was hier falsch gelaufen ist, und nichts tun kann, um das Problem zu beheben und drücken Sie den anwendungsweiten Ausnahmehandler, den ich habe, damit er ihn protokollieren kann. Dies ist bei einer InterruptedException nicht der Fall, sondern nur der Thread, der auf den Aufruf von interrupt () reagiert. Er löst die InterruptedException aus, um die Verarbeitung des Threads rechtzeitig abzubrechen.

Propagieren Sie also die InterruptedException, oder essen Sie sie intelligent (dh an einem Ort, an dem sie die beabsichtigten Aufgaben erfüllt hat), und setzen Sie das Interrupt-Flag zurück. Beachten Sie, dass das Interrupt-Flag gelöscht wird, wenn die InterruptedException ausgelöst wird. Die JDK-Bibliotheksentwickler gehen davon aus, dass das Abfangen der Ausnahme der Behandlung gleichkommt. Daher ist das Flag standardmäßig deaktiviert.

Der erste Weg ist also definitiv besser, das zweite Beispiel in der Frage ist nicht nützlich, es sei denn, Sie erwarten, dass der Thread tatsächlich unterbrochen wird, und das Unterbrechen führt zu einem Fehler.

Hier ist eine Antwort, die ich geschrieben habe mit einem Beispiel, wie Interrupts funktionieren . Sie können im Beispielcode sehen, wo die InterruptedException verwendet wird, um eine while-Schleife in der run-Methode des Runnable zu beenden.

12
Nathan Hughes

Die richtige Standardeinstellung ist das Hinzufügen von InterruptedException zu Ihrer Wurfliste. Ein Interrupt zeigt an, dass ein anderer Thread das Ende Ihres Threads wünscht. Der Grund für diese Anforderung ist nicht ersichtlich und vollständig kontextbezogen. Wenn Sie also über keine zusätzlichen Kenntnisse verfügen, sollten Sie davon ausgehen, dass es sich nur um ein benutzerfreundliches Herunterfahren handelt und alles, was dieses Herunterfahren vermeidet, eine nicht benutzerfreundliche Antwort ist.

Java wirft InterruptedException nicht zufällig aus, alle Ratschläge haben keine Auswirkung auf Ihre Anwendung, aber ich bin auf einen Fall gestoßen, in dem es für Entwickler sehr unpraktisch wurde, die "Swallow" -Strategie zu befolgen. Ein Team hatte eine große Anzahl von Tests entwickelt und Thread.Sleep viel verwendet. Jetzt haben wir begonnen, die Tests auf unserem CI-Server auszuführen, und manchmal blieben Fehler im Code in permanenten Wartezeiten stecken. Wenn versucht wird, den CI-Job abzubrechen, wurde die Situation zu verschlechtern, da der Thread.Interrupt, der den Test abbrechen sollte, den Job nicht abbrach. Wir mussten uns in die Box einloggen und die Prozesse manuell beenden.

Wenn Sie einfach die InterruptedException auslösen, stimmen Sie mit der Standardabsicht überein, dass Ihr Thread enden soll. Wenn Sie Ihrer Auslöserliste keine InterruptedException hinzufügen können, würde ich sie in eine RuntimeException einschließen.

Es gibt ein sehr rationales Argument dafür, dass InterruptedException selbst eine RuntimeException sein sollte, da dies eine bessere "Standard" -Behandlung fördern würde. Es ist keine RuntimeException, nur weil sich die Designer an eine kategoriale Regel hielten, nach der eine RuntimeException einen Fehler in Ihrem Code darstellen sollte. Da eine InterruptedException nicht direkt aus einem Fehler in Ihrem Code resultiert, ist dies nicht der Fall. In der Realität tritt jedoch häufig eine InterruptedException auf, weil in Ihrem Code ein Fehler vorliegt (z. B. Endlosschleife, Deadlock), und der Interrupt ist eine andere Thread-Methode zur Behandlung dieses Fehlers.

Wenn Sie wissen, dass rational aufgeräumt werden muss, dann tun Sie es. Wenn Sie eine tiefere Ursache für den Interrupt kennen, können Sie eine umfassendere Behandlung übernehmen.

Zusammenfassend sollten Ihre Auswahlmöglichkeiten für die Handhabung dieser Liste folgen:

  1. Standardmäßig zu Würfen hinzufügen.
  2. Wenn das Hinzufügen zu Würfen nicht zulässig ist, werfen Sie RuntimeException (e). (Beste Wahl aus mehreren schlechten Optionen)
  3. Nur wenn Sie eine explizite Ursache für den Interrupt kennen, können Sie ihn wie gewünscht behandeln. Wenn Ihre Behandlung lokal für Ihre Methode ist, setzen Sie sie zurück, unterbrochen durch einen Aufruf von Thread.currentThread (). Interrupt ().
9
nedruod

Ich wollte nur eine letzte Option zu dem hinzufügen, was die meisten Leute und Artikel erwähnen. Wie mR_fr0g festgestellt hat, ist es wichtig, den Interrupt korrekt zu behandeln, entweder durch:

  • Weitergabe der InterruptException

  • Unterbrechungsstatus auf Thread wiederherstellen

Oder zusätzlich:

  • Benutzerdefinierte Behandlung von Interrupts

Es ist nichts Falsches daran, den Interrupt in Abhängigkeit von Ihren Umständen benutzerdefiniert zu behandeln. Da es sich bei einem Interrupt um eine Aufforderung zur Beendigung und nicht um einen erzwungenen Befehl handelt, ist es durchaus zulässig, zusätzliche Arbeiten auszuführen, damit die Anwendung die Aufforderung ordnungsgemäß verarbeiten kann. Wenn ein Thread beispielsweise in den Energiesparmodus versetzt wird und auf IO) oder eine Hardwareantwort wartet, wenn er den Interrupt empfängt, ist es vollkommen gültig, alle Verbindungen ordnungsgemäß zu schließen, bevor der Thread beendet wird.

Ich empfehle dringend, das Thema zu verstehen, aber dieser Artikel ist eine gute Informationsquelle: http://www.ibm.com/developerworks/Java/library/j-jtp05236/

3
TheIT

Ich würde in einigen Fällen sagen, dass es in Ordnung ist, nichts zu tun. Wahrscheinlich nicht etwas, das Sie standardmäßig tun sollten, aber für den Fall, dass der Interrupt nicht stattfinden kann, bin ich mir nicht sicher, was ich sonst tun soll (wahrscheinlich ein Protokollierungsfehler, der den Programmfluss jedoch nicht beeinträchtigt).

Ein Fall wäre, wenn Sie eine Task-Warteschlange (Blockierungswarteschlange) haben. Falls Sie einen Daemon-Thread haben, der diese Aufgaben ausführt, und Sie den Thread nicht selbst unterbrechen (meines Wissens unterbricht der JVM die Daemon-Threads beim Herunterfahren von JVM nicht), sehe ich keine Möglichkeit, dass der Interrupt auftritt, und daher könnte dies der Fall sein einfach ignoriert. (Ich weiß, dass ein Daemon-Thread von der JVM jederzeit beendet werden kann und daher in einigen Fällen ungeeignet ist.).

BEARBEITEN: Ein weiterer Fall könnten geschützte Blöcke sein, zumindest basierend auf dem Tutorial von Oracle unter: http://docs.Oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

0
Bjarne Boström