Warum Thread.currentThread.interrupt () in einem catch InterruptException-Block aufrufen?


Antworten:


160

Dies geschieht, um den Zustand zu erhalten .

Wenn Sie das fangen InterruptExceptionund es schlucken, verhindern Sie im Wesentlichen, dass übergeordnete Methoden / Thread-Gruppen den Interrupt bemerken. Was zu Problemen führen kann.

Durch Aufrufen setzen Thread.currentThread().interrupt()Sie das Interrupt-Flag des Threads, damit Interrupt-Handler höherer Ebenen es bemerken und es entsprechend behandeln können.

Java Concurrency in Practice beschreibt dies ausführlicher in Kapitel 7.1.3: Reagieren auf Unterbrechungen . Ihre Regel lautet:

Nur Code, der die Unterbrechungsrichtlinie eines Threads implementiert, kann eine Unterbrechungsanforderung verschlucken. Allzweck-Task und Bibliothekscode sollten niemals Unterbrechungsanforderungen verschlucken.


15
In der Dokumentation heißt es: "Gemäß der Konvention InterruptedException löscht jede Methode, die durch Auslösen eines Interrupt-Status beendet wird, dies. Ich denke, dies macht die Antwort klarer, warum Sie den Interrupt-Status beibehalten müssen.
Stelios Adamantidis

Es ist auch erwähnenswert, dass interrupt()Anruf ist der einzige Weg setzen die unterbrochene Flag , wenn Sie Benachrichtigung über diesen Zustand durch den anderen „Liefermechanismus“ erhalten - das InterruptedExceptionwünscht oder nicht , es erneut zu werfen.
Sevo

67

Ich denke, dieses Codebeispiel macht die Dinge ein bisschen klar. Die Klasse, die den Job macht:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

Die Hauptklasse:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Versuchen Sie, Interrupt aufzurufen, ohne den Status zurückzusetzen.


13
so ist die Schlussfolgerung?
Scott 16 理论

3
Vielen Dank. Ich verstehe, was du jetzt meinst: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

Hinweis:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Wie stoppe ich einen Thread, der lange wartet (z. B. auf Eingabe)?

Damit diese Technik funktioniert, ist es wichtig, dass jede Methode, die eine Interrupt-Ausnahme abfängt und nicht bereit ist, damit umzugehen, die Ausnahme sofort erneut bestätigt. Wir sagen eher erneutes Setzen als erneutes Werfen, da es nicht immer möglich ist, die Ausnahme erneut zu werfen. Wenn die Methode, die die InterruptedException abfängt, nicht deklariert ist, um diese (aktivierte) Ausnahme auszulösen, sollte sie sich mit der folgenden Beschwörung "erneut unterbrechen":

Thread.currentThread().interrupt();

Dadurch wird sichergestellt, dass der Thread die InterruptedException erneut aktiviert, sobald dies möglich ist.


2

Ich würde es als schlechte Praxis oder zumindest ein bisschen riskant betrachten. Normalerweise führen übergeordnete Methoden keine Blockierungsvorgänge aus und werden dort nie angezeigt InterruptedException. Wenn Sie es an jedem Ort maskieren, an dem Sie einen unterbrechbaren Betrieb ausführen, werden Sie es nie bekommen.

Der einzige Grund dafür Thread.currentThread.interrupt(), dass keine andere Ausnahme oder Signalisierungsunterbrechungsanforderung auf andere Weise ausgelöst wird (z. B. Festlegen einer interruptedlokalen Variablenvariablen in der Hauptschleife eines Threads), ist die Situation, in der Sie mit der Ausnahme wirklich nichts tun können, wie in den finallyBlöcken.

Sehen Sie sich die Antwort von Péter Török an, wenn Sie die Auswirkungen des Thread.currentThread.interrupt()Anrufs besser verstehen möchten .


0

Siehe Java-Dokument

Wenn dieser Thread bei einem Aufruf von wait (), join (), sleep (long) blockiert wird, wird sein Interrupt-Status gelöscht und eine InterruptedException empfangen.

Wenn dieser Thread in einer E / A-Operation blockiert wird, wird der Interrupt-Status des Threads festgelegt und der Thread erhält eine ClosedByInterruptException.

Wenn dieser Thread in einem Selector blockiert ist, wird der Interrupt-Status des Threads gesetzt und er kehrt sofort von der Auswahloperation zurück.

Wenn keine der vorherigen Bedingungen erfüllt ist, wird der Interrupt-Status dieses Threads festgelegt.

Wenn Sie also die sleepBabySleep () -Methode in @Ajay George Answer to I / O-Operation oder nur ein Sysout ändern, müssen Sie den Status nicht zurücksetzen, um das Programm zu stoppen. (Übrigens werfen sie nicht einmal InterruptedException)

Genau wie @ Péter Török sagte => Dies geschieht, um den Zustand zu erhalten. (Und insbesondere für Methoden, die InterruptedException auslösen)

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.