Perché invocare Thread.currentThread.interrupt () in un blocco InterruptException catch?


Risposte:


160

Questo viene fatto per mantenere lo stato .

Quando lo prendi InterruptExceptione lo inghiotti, essenzialmente impedisci a qualsiasi metodo / gruppo di thread di livello superiore di notare l'interrupt. Che può causare problemi.

Chiamando Thread.currentThread().interrupt(), si imposta il flag di interrupt del thread, in modo che i gestori di interrupt di livello superiore lo notino e possano gestirlo in modo appropriato.

Java Concurrency in Practice ne discute più dettagliatamente nel Capitolo 7.1.3: Risposta all'interruzione . La sua regola è:

Solo il codice che implementa la politica di interruzione di un thread può ingoiare una richiesta di interruzione. L'attività generale e il codice della libreria non devono mai ingoiare le richieste di interruzione.


15
Nella documentazione si afferma che "Per convenzione, qualsiasi metodo che esce lanciando uno InterruptedException stato di interruzione cancella quando lo fa. Penso che questo renda la risposta più chiara in termini di perché è necessario preservare lo stato di interruzione.
Stelios Adamantidis

Vale anche la pena notare che la interrupt()chiamata è l'unico modo per impostare il flag interrotto una volta ricevuta la notifica su questo stato attraverso l'altro "meccanismo di consegna" - InterruptedExceptione desideri o non riesci a rilanciarlo.
sevo

67

Penso che questo esempio di codice renda le cose un po 'chiare. La classe che svolge il lavoro:

   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();
            }
        }
    }

La classe principale:

   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();
        }

    }

Prova a chiamare l'interruzione senza ripristinare lo stato.


13
quindi la conclusione è ??
Scott 混合 理论 il

3
Grazie. Capisco cosa intendi ora: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

Nota:

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

Come posso interrompere un thread che attende per lunghi periodi (ad esempio, per l'input)?

Perché questa tecnica funzioni, è fondamentale che qualsiasi metodo che intercetta un'eccezione di interruzione e non sia pronto a gestirla riafferma immediatamente l'eccezione. Diciamo riassestamenti piuttosto che riprogrammazioni, perché non è sempre possibile riproporre l'eccezione. Se il metodo che intercetta InterruptedException non viene dichiarato per lanciare questa (verificata) eccezione, dovrebbe "reinterrarsi" con il seguente incantesimo:

Thread.currentThread().interrupt();

Ciò garantisce che il thread rilancierà InterruptedException non appena sarà in grado.


2

Lo considero una cattiva pratica o almeno un po 'rischiosa. Solitamente i metodi di livello superiore non eseguono operazioni di blocco e non vedranno maiInterruptedException lì. Se lo maschera in ogni luogo in cui esegui un'operazione interrompibile, non lo otterrai mai.

L'unica logica per Thread.currentThread.interrupt()e non sollevare alcuna altra eccezione o segnalare la richiesta di interruzione in altro modo (ad es. Impostare interruptedla variabile variabile locale nel ciclo principale di un thread) è la situazione in cui non è possibile fare nulla con l'eccezione, come nei finallyblocchi.

Vedi la risposta di Péter Török, se vuoi capire meglio le implicazioni della Thread.currentThread.interrupt()chiamata.


0

Fare riferimento a java doc

Se questo thread viene bloccato in un richiamo di wait (), join (), sleep (long), il suo stato di interruzione verrà cancellato e riceverà una InterruptedException.

Se questo thread viene bloccato in un'operazione I / O, verrà impostato lo stato di interruzione del thread e il thread riceverà un ClosedByInterruptException.

Se questo thread è bloccato in un Selettore, lo stato di interruzione del thread verrà impostato e tornerà immediatamente dall'operazione di selezione.

Se nessuna delle condizioni precedenti è valida, verrà impostato lo stato di interruzione di questo thread.

Quindi, se si modifica il metodo sleepBabySleep () in @Ajay George Risposta all'operazione I / O o solo un sysout, non è necessario ripristinare lo stato per arrestare il programma. (A proposito, non lanciano nemmeno InterruptedException)

Proprio come @ Péter Török ha detto => Questo è fatto per mantenere lo stato. (E in particolare per il metodo che genererà InterruptedException)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.