Was ist der Unterschied zwischen den folgenden Arten der Handhabung InterruptedException
? Was ist der beste Weg, um es zu tun?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
ODER
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
EDIT: Ich möchte auch wissen, in welchen Szenarien diese beiden verwendet werden.
Antworten:
Sie sind wahrscheinlich gekommen, um diese Frage zu stellen, weil Sie eine Methode aufgerufen haben, die wirft
InterruptedException
.Zunächst sollten Sie sehen,
throws InterruptedException
was es ist: Ein Teil der Methodensignatur und ein mögliches Ergebnis des Aufrufs der von Ihnen aufgerufenen Methode. Beginnen Sie also damit, die Tatsache zu berücksichtigen, dass anInterruptedException
ein perfekt gültiges Ergebnis des Methodenaufrufs ist.Was sollte Ihre Methode tun , wenn die von Ihnen aufgerufene Methode eine solche Ausnahme auslöst? Sie können die Antwort herausfinden, indem Sie über Folgendes nachdenken:
Ist es für die Methode, die Sie implementieren , sinnvoll , eine zu werfen
InterruptedException
? Anders ausgedrückt ist einInterruptedException
vernünftiges Ergebnis beim Aufrufen Ihrer Methode?Wenn ja , dann
throws InterruptedException
sollte ein Teil von sein Ihrer Methodensignatur sein, und Sie sollten die Ausnahme verbreiten lassen (dh sie überhaupt nicht abfangen).Wenn nein , sollten Sie Ihre Methode nicht mit deklarieren
throws InterruptedException
und die Ausnahme abfangen (müssen!). In dieser Situation sind nun zwei Dinge zu beachten:Jemand hat Ihren Thread unterbrochen. Dieser Jemand ist wahrscheinlich bestrebt, den Vorgang abzubrechen, das Programm ordnungsgemäß zu beenden oder was auch immer. Sie sollten höflich zu dieser Person sein und ohne weiteres von Ihrer Methode zurückkehren.
Auch wenn Ihre Methode im Falle einer
InterruptedException
Unterbrechung des Threads einen vernünftigen Rückgabewert erzielen kann, kann dies dennoch von Bedeutung sein. Insbesondere der Code, der Ihre Methode aufruft, kann daran interessiert sein, ob während der Ausführung Ihrer Methode eine Unterbrechung aufgetreten ist. Sie sollten daher die Tatsache protokollieren, dass eine Unterbrechung stattgefunden hat, indem Sie das unterbrochene Flag setzen:Thread.currentThread().interrupt()
Inzwischen sollte klar sein, dass
throw new RuntimeException(e)
es eine schlechte Idee ist , nur etwas zu tun . Es ist nicht sehr höflich zum Anrufer. Sie könnten eine neue Laufzeitausnahme erfinden, aber die Grundursache (jemand möchte, dass der Thread die Ausführung stoppt) geht möglicherweise verloren.Andere Beispiele:
Dieser Beitrag wurde bereits als ein Artikel neu geschrieben hier .
quelle
interrupt()
, um den unterbrochenen Status beizubehalten. Was ist der Grund dafür, dies nicht auf einem zu tunThread.sleep()
?Thread.currentThread.interrupt()
einesInterruptedException
catch-Blocks setzt nur das Interrupt-Flag. Es wird nicht dazu führen, dass ein andererInterruptedException
in einen äußerenInterruptedException
Fangblock geworfen / gefangen wird .Zufällig habe ich heute Morgen auf meinem Weg zur Arbeit in Java Concurrency In Practice von Brian Goetz gerade darüber gelesen . Grundsätzlich sagt er, Sie sollten eines von drei Dingen tun
Propagieren Sie das
InterruptedException
- Deklarieren Sie Ihre Methode, um das Häkchen zu werfen,InterruptedException
damit Ihr Anrufer damit umgehen muss.Interrupt wiederherstellen - Manchmal kann man nicht werfen
InterruptedException
. In diesen Fällen sollten SieInterruptedException
den Interrupt-Status abfangen und wiederherstellen, indem Sie dieinterrupt()
Methode auf dem aufrufen,currentThread
damit der Code weiter oben im Aufrufstapel erkennt, dass ein Interrupt ausgegeben wurde, und schnell von der Methode zurückkehren. Hinweis: Dies gilt nur, wenn Ihre Methode über die Semantik "Try" oder "Best Effort" verfügt, dh nichts Kritisches passiert, wenn die Methode ihr Ziel nicht erreicht. Zum Beispiellog()
odersendMetric()
kann eine solche Methode sein oderboolean tryTransferMoney()
, aber nichtvoid transferMoney()
. Sehen Sie hier für weitere Details.Uninterruptibles
. B. über Guavas .Uninterruptibles
Übernehmen Sie den Boilerplate-Code wie im Beispiel für nicht stornierbare Aufgaben in JCIP § 7.1.3.quelle
Was versuchst du zu machen?
Das
InterruptedException
wird ausgelöst, wenn ein Thread wartet oder schläft und ein anderer Thread ihn mit derinterrupt
Methode in der Klasse unterbrichtThread
. Wenn Sie diese Ausnahme abfangen, bedeutet dies, dass der Thread unterbrochen wurde. Normalerweise macht es keinen Sinn anzurufenThread.currentThread().interrupt();
erneut , es sei denn, Sie möchten den "unterbrochenen" Status des Threads von einer anderen Stelle aus überprüfen.In Bezug auf Ihre andere Möglichkeit, ein zu werfen
RuntimeException
, scheint es nicht sehr klug zu sein (wer wird das fangen? Wie wird es gehandhabt?), Aber es ist schwierig, ohne zusätzliche Informationen mehr zu erzählen.quelle
Thread.currentThread().interrupt()
setzt das unterbrochene Flag (erneut), was in der Tat nützlich ist, wenn sichergestellt werden soll, dass der Interrupt auf einer höheren Ebene bemerkt und verarbeitet wird.Für mich ist das Wichtigste daran: Eine InterruptedException ist nichts, was schief geht, es ist der Thread, der das tut, was Sie ihm gesagt haben. Daher macht es keinen Sinn, es erneut in eine RuntimeException zu werfen.
In vielen Fällen ist es sinnvoll, eine in eine RuntimeException eingeschlossene Ausnahme erneut auszulösen, wenn Sie sagen, ich weiß nicht, was hier schief gelaufen ist, und ich kann nichts tun, um das Problem zu beheben. Ich möchte nur, dass es aus dem aktuellen Verarbeitungsablauf herauskommt und klicken Sie auf den anwendungsweiten Ausnahmebehandler, den ich habe, damit er protokolliert werden kann. Dies ist bei einer InterruptedException nicht der Fall. Es handelt sich lediglich um den Thread, der auf den Aufruf von Interrupt () reagiert. Er löst die InterruptedException aus, um die Verarbeitung des Threads rechtzeitig abzubrechen.
Verbreiten Sie also die InterruptedException oder essen Sie sie intelligent (dh an einem Ort, an dem sie das erreicht hat, was sie tun sollte) und setzen Sie das Interrupt-Flag zurück. Beachten Sie, dass das Interrupt-Flag gelöscht wird, wenn die InterruptedException ausgelöst wird. Die Entwickler der Jdk-Bibliothek gehen davon aus, dass das Abfangen der Ausnahme der Behandlung entspricht. Daher wird das Flag standardmäßig gelöscht.
Der erste Weg ist also definitiv besser. Das zweite Beispiel in der Frage ist nur dann nützlich, wenn Sie nicht erwarten, dass der Thread tatsächlich unterbrochen wird, und wenn Sie ihn unterbrechen, ist dies ein Fehler.
Hier ist eine Antwort, die ich geschrieben habe und die beschreibt, wie Interrupts funktionieren, anhand eines Beispiels . Sie können im Beispielcode sehen, wo die InterruptedException verwendet wird, um aus einer while-Schleife in der Run-Methode von Runnable auszusteigen.
quelle
Die richtige Standardauswahl ist das Hinzufügen von InterruptedException zu Ihrer Wurfliste. Ein Interrupt zeigt an, dass ein anderer Thread wünscht, dass Ihr Thread endet. Der Grund für diese Anfrage wird nicht offensichtlich und ist vollständig kontextbezogen. Wenn Sie also keine zusätzlichen Kenntnisse haben, sollten Sie davon ausgehen, dass es sich nur um ein freundliches Herunterfahren handelt, und alles, was dieses Herunterfahren vermeidet, ist eine nicht freundliche Antwort.
Java wird InterruptedException's nicht zufällig auslösen. Alle Ratschläge wirken sich nicht auf Ihre Anwendung aus, aber ich bin auf einen Fall gestoßen, in dem Entwickler, die der "Swallow" -Strategie folgen, sehr unpraktisch wurden. 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 steckten aufgrund von Fehlern im Code permanente Wartezeiten fest. Um die Situation zu verschlimmern, wurde beim Versuch, den CI-Job abzubrechen, nie geschlossen, 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.
Kurz gesagt, wenn Sie einfach die InterruptedException auslösen, stimmen Sie mit der Standardabsicht überein, dass Ihr Thread enden soll. Wenn Sie InterruptedException nicht zu Ihrer Wurfliste 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 die Designer an einer kategorischen Regel festhielten, dass eine RuntimeException einen Fehler in Ihrem Code darstellen sollte. Da eine InterruptedException nicht direkt aus einem Fehler in Ihrem Code entsteht, ist dies nicht der Fall. Die Realität ist jedoch, dass häufig eine InterruptedException auftritt, weil ein Fehler in Ihrem Code vorliegt (z. B. Endlosschleife, Deadlock), und der Interrupt eine Methode eines anderen Threads zur Behandlung dieses Fehlers ist.
Wenn Sie wissen, dass eine rationale Bereinigung durchgeführt werden muss, dann tun Sie es. Wenn Sie eine tiefere Ursache für den Interrupt kennen, können Sie eine umfassendere Behandlung übernehmen.
Zusammenfassend sollte Ihre Auswahl für die Handhabung dieser Liste folgen:
quelle
Ich wollte nur eine letzte Option zu dem hinzufügen, was die meisten Leute und Artikel erwähnen. Wie mR_fr0g angegeben hat, ist es wichtig, den Interrupt korrekt zu behandeln, entweder durch:
Weitergabe der InterruptException
Stellen Sie den Interrupt-Status des Threads wieder her
Oder zusätzlich:
Es ist nichts Falsches daran, den Interrupt abhängig von Ihren Umständen auf benutzerdefinierte Weise zu behandeln. Da ein Interrupt eine Anforderung zur Beendigung ist, im Gegensatz zu einem erzwungenen Befehl, ist es durchaus gültig, zusätzliche Arbeiten abzuschließen, damit die Anwendung die Anforderung ordnungsgemäß verarbeiten kann. Wenn ein Thread beispielsweise in den Ruhezustand wechselt und auf E / A 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/
quelle
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 falls es keine Möglichkeit für den Interrupt geben sollte, bin ich mir nicht sicher, was ich sonst tun soll (wahrscheinlich Protokollierungsfehler, aber das hat keinen Einfluss auf den Programmfluss).
Ein Fall wäre, wenn Sie eine Task-Blockierwarteschlange haben. Falls Sie einen Daemon-Thread haben, der diese Aufgaben erledigt, und Sie den Thread nicht selbst unterbrechen (meines Wissens unterbricht der JVM die Daemon-Threads beim Herunterfahren des JVM nicht), sehe ich keine Möglichkeit für den Interrupt, und daher könnte es sein einfach ignoriert. (Ich weiß, dass ein Daemon-Thread jederzeit vom JVM beendet werden kann und daher in einigen Fällen ungeeignet ist).
BEARBEITEN: Ein anderer 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
quelle