Vorwort
Für die InterruptedException besteht eine häufige Art des Umgangs darin, es zu "zu schlucken" - fangen Sie es und tun Sie nichts (oder es ist nicht viel besser) - genau wie die Auflistung von 4 später. Leider ignoriert dieser Ansatz die Tatsache, dass in diesem Zeitraum Interrupts auftreten können, und Interrupts können dazu führen, dass die Anwendung die Fähigkeit verliert, Aktivität zu stornieren oder sie rechtzeitig zu schließen.
Blockierungsmethode
Wenn eine Methode eine InterruptedException auswirkt, wird nicht nur angegeben, dass sie eine bestimmte Check -Ausnahme ausführen kann, sondern auch etwas anderes sagt. Zum Beispiel zeigt es Ihnen, dass es sich um eine Blockierungsmethode handelt, mit der versucht wird, die Blockierung zu beseitigen und so früh wie möglich zurückzukehren, wenn Sie richtig reagieren.
Die Blockierungsmethode unterscheidet sich von der allgemeinen Methode, deren Ausführen lange dauert. Der Abschluss einer allgemeinen Methode hängt nur davon ab, was es tut und ob genügend Rechenressourcen verfügbar sind (CPU -Zyklen und Speicher). Die Fertigstellung der Blockierungsmethode hängt auch von einigen externen Ereignissen ab, wie z. B. Timer -Ablauf, E/A -Fertigstellung oder Aktionen eines anderen Threads (Freilassung ein Sperren, ein Flag festlegen oder eine Aufgabe in eine Arbeitswarteschlange platzieren). Allgemeine Methoden enden, nachdem ihre Arbeit durchgeführt wurde, während Blockierungsmethoden schwieriger vorherzusagen sind, da sie von externen Ereignissen abhängen. Blockierungsmethoden können die Reaktionsfähigkeit beeinflussen, da es schwierig ist, vorherzusagen, wann sie enden werden.
Die Blockierungsmethode wird möglicherweise nicht beendet, da sie nicht auf das Ereignis warten kann, auf das sie wartet. Daher ist es sehr nützlich, die Blockierungsmethode stornierbar zu machen (und es ist oft sehr nützlich, wenn lang laufende nicht blockierende Methoden stornierbar sind). Ein stornierbarer Betrieb bezieht sich auf einen Betrieb, der vor dem normalen Abschluss von außen gekündigt werden kann. Der durch Thread.Sleep () und Object.wait () unterstützte und stützende Interrupt -Mechanismus ist ein Stornungsmechanismus; Damit kann ein Thread einen anderen Thread anfordern, das zu stoppen, was er tut. Wenn eine Methode eine InterruptedException auswirkt, wird Ihnen gesagt, dass wenn der Thread, der die Methode ausführt, unterbrochen wird, versucht wird, das zu stoppen, was er tut, und im Voraus zurückzukehren, und durch das Werfen einer InterruptedException kehrt sie im Voraus zurück. Eine gut erzogene Blockierungsbibliotheksmethode sollte auf Interrupts reagieren und eine InterruptedException werfen, damit sie in stornierbaren Aktivitäten verwendet werden kann, ohne die Antwort zu beeinflussen.
Thread Interrupt
Jeder Thread ist ein boolescher Attribut zugeordnet, der den unterbrochenen Status des Threads darstellt. Der Interrupt -Zustand ist zu Beginn falsch; Wenn ein anderer Thread einen Thread unterbricht, indem er Thread aufruft.interrupt (), tritt eine von zwei Situationen auf. Wenn dieser Thread eine unterbrachbare Blockierungsmethode mit niedrigem Niveau ausführt, wie z. Andernfalls legt Interrupt () nur den Interrupt -Status des Threads fest. Nachdem der im unterbrochene Thread ausgeführte Code den Interrupt -Status befragt hat, um festzustellen, ob er aufgefordert wird, das zu stoppen, was er tut. Der Interrupt -Status kann mit Thread gelesen werden. ISBETINGEDDED () und kann durch einen Operation namens Thread gelesen und gelöscht werden.Interrupted ().
Unterbrechung ist ein kollaborativer Mechanismus. Wenn ein Thread einen anderen Thread unterbricht, stoppt der unterbrochene Thread nicht unbedingt, was er sofort tut. Stattdessen ist ein Interrupt eine höfliche Anfrage an einen anderen Thread, um zu stoppen, was er tut, wenn er bereit und bequem ist. Einige Methoden wie Thread.sleep () nehmen solche Anforderungen sehr ernst, aber jede Methode reagiert nicht unbedingt auf Interrupts. Bei Interrupt -Anfragen können Methoden, die nicht blockieren, aber noch lange dauern, den Interrupt -Status abfragen und im Voraus zurückkehren, wenn sie unterbrochen werden. Sie können Interrupt -Anfragen nach Belieben ignorieren, aber dies wirkt sich auf die Antwort aus.
Ein Vorteil des kollaborativen Charakters von Unterbrechungen besteht darin, dass es eine größere Flexibilität bietet, um stornierbare Aktivitäten sicher zu konstruieren. Wir wollen selten, dass eine Aktivität sofort aufhört; Wenn die Aktivität während eines Updates abgebrochen wird, kann die Programmdatenstruktur inkonsistent sein. Der Interrupt ermöglicht es einer stornierbaren Aktivität, laufende Arbeiten zu beseitigen, Invarianten wiederherzustellen und andere Aktivitäten zu benachrichtigen, die vor dem Kündigen abgesagt werden sollen.
Handle InterruptedException
Wenn das Werfen einer InterruptedException bedeutet, dass eine Methode eine Blockierungsmethode ist, bedeutet das Aufrufen einer Blockierungsmethode, dass Ihre Methode auch eine Blockierungsmethode ist und Sie eine Strategie haben sollten, um die InterruptedException zu bewältigen. Die einfachste Strategie besteht normalerweise darin, selbst eine InterruptedException zu werfen, wie im Code in den Methoden Puttask () und Gettask () in Auflistung 1 gezeigt. Dies lässt die Methode auf Interrupts reagieren und einfach eine InterruptedException in die Throws -Klausel hinzufügen.
Auflistung 1. Nicht unterbrochene InterruptedException aufnehmen, sie an den Anrufer ausbreiten
public class TaskQueue {private statische endgültige int max_tasks = 1000; private blockingQueue <Abum> queue = new LinkedBlockingQueue <Dask> (max_tasks); public void puttask (Aufgabe R) löst InterruptedException {queue.put (r) aus; } public task gettask () löscht InterruptedException {return queue.take (); }} Manchmal sind einige Reinigungsarbeiten erforderlich, bevor die Ausnahme ausbreitet. In diesem Fall können Sie die InterruptedException fangen, eine Aufräumarbeiten durchführen und dann eine Ausnahme machen. Listing 2 zeigt diese Technik, einen Mechanismus, der für Spieler in Online -Spieldiensten entspricht. Die MatchPlayers () -Methode wartet darauf, dass zwei Spieler ankommen und dann ein neues Spiel starten. Wenn die Methode unterbrochen wird, wenn ein Spieler angekommen ist, ein anderer Spieler nicht angekommen ist, wird dieser Spieler wieder in die Warteschlange gestellt und InterruptedException angewendet, damit die Anfrage des Spielers an das Spiel nicht verloren geht.
Listing 2. Aufgabenspezifische Aufräumarbeiten durchführen
public class Playmerather {private Playerource -Spieler; Public PlayerMatcher (Playerource -Spieler) {this.players = Player; } public void MatchPlayer () löst InterruptedException aus {try {Player -PlayerOne, Playertwo; while (true) {PlayerOne = Playertwo = null; // Warten Sie, bis zwei Spieler ankommen und einen neuen Game Playerone = Player.waitforPlayer () starten; // könnte IE Playertwo = Players.waitforPlayer () werfen; // könnte IE startNewGame werfen (PlayerOne, Playertwo); }} catch (InterruptedException e) {// Wenn wir einen Spieler haben und unterbrochen wurden, geben Sie diesen Spieler zurück, wenn (PlayerOne! = null) Spieler.Addfirst (PlayerOne); // dann die Ausnahme propagieren. }}} Hör nicht auf, lebendig zu schlucken
Manchmal ist es nicht angemessen, eine InterruptedException zu werfen, beispielsweise, wenn eine durch ein Runnable definierte Aufgabe eine unterbrechbare Methode aufruft. In diesem Fall kann die InterruptedException nicht wieder durchdrungen werden, aber Sie möchten auch nichts tun. Wenn eine Blockierungsmethode einen Interrupt erkennt und eine InterruptedException wirft, löscht dies den Interrupt -Zustand. Wenn eine InterruptedException erfasst wird, aber nicht zurückgeworfen werden kann, sollte der Nachweis des Interrupts aufbewahrt werden, so dass Code im Rufstapel auf höherem Niveau den Interrupt kennen und darauf reagieren kann. Diese Aufgabe kann erledigt werden, indem Interrupt () aufgerufen wird, um den aktuellen Thread zu "neu interpretvieren", wie in Auflistung 3 gezeigt. Zumindest wenn eine InterruptedException gefangen wird und er nicht zurückgeworfen wird, wird der aktuelle Thread vor der Rückkehr erneut eingedrungen.
Auflistung 3. Wiederaufnahme des unterbrochenen Zustands nach der Erfassung der InterruptedException
public class taskRunner implementiert runnable {private blockingqueue <aufgabe> Warteschlange; public TaskRunner (BlockingQueue <Abum> Warteschlange) {this.queue = Queue; } public void run () {try {while (true) {Task task = queue.take (10, TimeUnit.seconds); task.execute (); }} catch (InterruptedException e) {// den unterbrochenen Status thread.currentThread (). Interrupt () wiederherstellen; }}} Das Schlimmste, was Sie mit InterruptedException zu tun haben, ist, es roh zu schlucken-fangen Sie es und stellen dann den Interrupt-Status des Threads weder wieder durch. Für eine Ausnahme, mit der Sie nicht wissen, wie Sie umgehen sollen, besteht die besten Möglichkeit, sie zu erfassen und aufzunehmen, aber diese Methode ist immer noch wie ein Roh-Interrupt, da Code auf höherer Ebene im Anrufstack immer noch keine Informationen über die Ausnahme erhalten kann. (Es ist nicht ratsam, nur InterruptedException aufzuzeichnen, da es zu spät ist, es zu verarbeiten, wenn jemand das Protokoll liest.) Auflistung 4 zeigt ein weit verbreitetes Muster, das auch ein Muster der Rohschluckenunterbrechung ist:
Liste 4. Rohschlucken Unterbrechung - Tun Sie dies nicht
// DIESE öffentliche Klasse TaskRunner implementiert Runnable {private BlockingQueue <Abum> Warteschlange; public TaskRunner (BlockingQueue <Abum> Warteschlange) {this.queue = Queue; } public void run () {try {while (true) {Task task = queue.take (10, TimeUnit.seconds); task.execute (); }} catch (InterruptedException geschluckt) { / * Tun Sie dies nicht - Stattdessen stellen Sie den unterbrochenen Status wieder her * /}}} Wenn die InterruptedException nicht zurückgeworfen werden kann, unabhängig davon, ob Sie die Interrupt-Anforderung verarbeiten möchten oder nicht, müssen Sie den aktuellen Thread weiterhin erneut einlegen, da eine Interrupt-Anforderung möglicherweise mehrere "Empfänger" aufweist. Die Worker -Thread -Thread -Implementierung von Thread -Threadpool (ThreadPoolexecutor) ist für die Unterbrechung verantwortlich. Daher kann die Unterbrechung einer Aufgabe in einem laufenden Thread -Pool einen doppelten Effekt haben. Einer besteht darin, die Aufgabe zu stornieren, und der andere soll den Ausführungs -Thread darüber informieren, dass der Thread -Pool geschlossen werden soll. Wenn die Aufgabe die Anfrage verschlingt, weiß der Worker -Thread nicht, dass ein angeforderter Interrupt vorliegt, wodurch das Herunterfahren der Anwendung oder des Dienstes verzögert wird.
Implementieren Sie stornierte Aufgaben
Es gibt keine spezifische Semantik für Interrupts in der Sprachspezifikation, aber in größeren Programmen ist es schwierig, die Interrupt -Semantik mit Ausnahme der Stornierung aufrechtzuerhalten. Abhängig von der Aktivität können Benutzer eine Stornierung über eine GUI oder einen Netzwerkmechanismus wie JMX oder Webdienst anfordern. Die Programmlogik kann auch zur Absage angefordert werden. Ein Web -Crawler wird beispielsweise automatisch geschlossen, wenn er erkennt, dass die Festplatte voll ist. Andernfalls startet ein paralleler Algorithmus mehrere Threads, um nach verschiedenen Bereichen des Lösungsraums zu suchen, und stornieren diese Threads, sobald einer der Threads eine Lösung findet.
Nur weil eine Aufgabe storniert werden kann, bedeutet dies nicht, dass eine Interrupt -Anfrage sofort beantwortet werden muss. Bei Aufgaben, die Code in einer Schleife ausführen, müssen normalerweise nur für jede Schleife Iteration nach Interrupts prüfen. Abhängig davon, wie lange die Schleife ausgeführt wird, kann es einige Zeit dauern, bis ein Code feststellt, dass der Thread unterbrochen wurde (entweder den Interrupt -Status, indem Sie den Thread aufrufen. Wenn die Aufgabe reaktionsschnell sein muss, kann sie den Interrupt -Zustand häufiger befragen. Die Blockierungsmethode befragt normalerweise den Interrupt -Zustand sofort am Einlass und wirkt, wenn sie die Reaktionsfähigkeit verbessern soll, auch eine InterruptedException.
Das einzige Mal, dass Sie am Leben aufhören können, zu schlucken, ist, dass Sie wissen, dass der Faden im Begriff ist, zu verlassen. Dieses Szenario tritt nur auf, wenn die Klasse, die die unterbrechungsvolle Methode aufruft, Teil des Threads ist, nicht ausgelastbar oder allgemeiner Bibliothekscode, wie in Auflistung 5. Auflistung 5 gezeigt, erstellt einen Thread, in dem Primatennummern aufgelistet sind, bis sie unterbrochen wird. Außerdem können Sie beenden, wenn er unterbrochen wird. Die Schleife, die zur Suche nach Primes -Überprüfungen nach Unterbrechungen an zwei Stellen verwendet wird: Eine besteht darin, die isinrupted () -Methode am Kopf der while -Schleife zu befragen, und der andere soll die Blockierungsmethode blockieren.put () aufrufen.
Listing 5. Wenn Sie wissen, dass der Thread beendet wird, können Sie den Interrupt schlucken
öffentliche Klasse PrimePRecer erweitert Thread {private final Blockingqueue <BigInteger> Warteschlange; PRIMEPROCER (BlockingQueue <BigInTeger> Queue) {this.queue = Queue; } public void run () {try {bigInteger p = bigInteger.one; while (! thread.currentThread (). isInterrupted ()) queue.put (p = P.NextProboBablePlable ()); } catch (InterruptedException konsumiert) { / * Erlauben Sie den Thread zum Beenden * /}} public void cancel () {interrupt (); }} Unbreakable Blockierungsmethode
Nicht alle Blockierungsmethoden werfen InterruptedException aus. Die Eingangs- und Ausgabestreamklassen blockieren, die darauf warten, dass die E/A abgeschlossen ist. Sie werfen jedoch nicht unterbrochen und kehren nicht im Voraus zurück, wenn sie unterbrochen werden. Für Socket -E/A wird jedoch der Blockierungs -E/A -Betrieb auf dieser Sockel früh abgeschlossen und eine SocketException wird geworfen. Die nicht blockierenden E/A-Klassen in Java.NIO unterstützen keine unterbrochene E/A, aber sie können auch entsperrt werden, indem sie den Kanal schließen oder auf dem Auswachen anfordern. In ähnlicher Weise kann der Versuch, ein internes Schloss (in einen synchronisierten Block einzutreten) zu erwerben, nicht unterbrochen werden, aber Reentrantlock unterstützt den unterbrochenen Erfassungsmodus.
Ungebundene Aufgaben
Einige Aufgaben weigern sich, unterbrochen zu werden, was sie ungeheuerlich macht. Selbst nicht anerkennbare Aufgaben sollten versuchen, den Interrupt-Status zu erhalten, falls der Code auf höherem Niveau auf dem Anrufstapel Interrupts nach Ablauf der nicht anerkennbaren Aufgaben verarbeiten muss. Das Listing 6 zeigt eine Methode, die auf eine blockierende Warteschlange wartet, bis ein verfügbares Element in der Warteschlange erscheint, unabhängig davon, ob es unterbrochen ist oder nicht. Aus Gründen der Bequemlichkeit wird der Interrupt -Zustand nach dem Ende in einem schließlich Block fortgesetzt, um den Anrufer nicht der Interrupt -Anfrage zu entziehen. (Es kann den Interrupt -Zustand nicht früher wieder aufnehmen, da dies eine unendliche Schleife verursacht - Blockingqueue.take () wird den Interrupt -Zustand am Eingang sofort befragen, und wenn der Interrupt -Zustand gefunden wird, wird eine InterruptedException geworfen.)
Auflistung 6. Unbeschaffte Aufgaben, die den unterbrochenen Zustand vor der Rückkehr wiederherstellen
öffentliche Aufgabe getNextTask (Blockingqueue <Abum> Warteschlange) {boolean interbruptd = false; try {while (true) {try {return queue.take (); } catch (InterruptedException e) {interbrupted = true; // durchfallen und wiederholen}}} endlich {if (unterbrochen) thread.currentThread (). Interrupt (); }} Zusammenfassen
Sie können den von der Java -Plattform bereitgestellten Zusammenarbeit -Interrupt -Mechanismus verwenden, um flexible Stornierungsstrategien zu konstruieren. Aktivitäten können nach eigenem Ermessen entscheiden, ob sie stornierbar oder nicht anerkennbar sind und wie auf Interrupts reagiert werden soll, und können auch Interrupts verschieben, wenn eine sofortige Rückgabe die Anwendungsintegrität beeinträchtigen würde. Auch wenn Sie Interrupts in Ihrem Code vollständig ignorieren möchten, sollten Sie sicherstellen, dass der Interrupt-Status wiederhergestellt wird, ohne ihn zu wiederholen, damit der Code nicht weiß, was der Interrupt passiert. Das obige ist der vollständige Inhalt von Javas Theorie und Praxis, InterruptedException -Ausnahmen zu behandeln. Ich hoffe, dieser Artikel wird Ihnen hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie bitte eine Nachricht zur Diskussion.