¿Por qué invocar Thread.currentThread.interrupt () en un bloque catch InterruptException?

Respuestas:

160

Esto se hace para mantener el estado .

Cuando lo atrapa InterruptExceptiony lo traga, esencialmente evita que cualquier método de nivel superior / grupo de hilos note la interrupción. Lo que puede causar problemas.

Llamando Thread.currentThread().interrupt() , establece el indicador de interrupción del subproceso, para que los manejadores de interrupciones de nivel superior lo noten y puedan manejarlo adecuadamente.

La concurrencia de Java en la práctica analiza esto con más detalle en el Capítulo 7.1.3: Respuesta a la interrupción . Su regla es:

Solo el código que implementa la política de interrupción de un hilo puede tragarse una solicitud de interrupción. La tarea de propósito general y el código de la biblioteca nunca deben tragarse las solicitudes de interrupción.

Péter Török
fuente
15
En la documentación se afirma que "Por convención, cualquier método que sale por lanzar una InterruptedException borra Alarma de estado cuando lo hace. Creo que esto hace que la respuesta más clara en cuanto a la razón por la que necesita para preservar el estado de interrupción.
Stelios Adamantidis
También vale la pena señalar que la interrupt()llamada es la única forma de establecer el indicador interrumpido una vez que recibió una notificación sobre este estado a través del otro "mecanismo de entrega": el InterruptedExceptiony desea o no puede volver a lanzarlo.
sevo
67

Creo que este ejemplo de código aclara un poco las cosas. La clase que hace el trabajo:

   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 clase principal:

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

    }

Intente llamar a interrupción sin volver a configurar el estado.

Ajay George
fuente
13
entonces la conclusión es ??
Scott 混合 理论
3
Gracias. Ahora veo lo que quiere decir: repl.it/@djangofan/InterruptedThreadExample
djangofan
20

Nota:

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

¿Cómo detengo un hilo que espera durante largos períodos (por ejemplo, para la entrada)?

Para que esta técnica funcione, es fundamental que cualquier método que detecte una excepción de interrupción y que no esté preparado para tratarla reactive inmediatamente la excepción. Decimos reiniciar en lugar de volver a lanzar, porque no siempre es posible volver a lanzar la excepción. Si no se declara que el método que detecta la InterruptedException produce esta excepción (marcada), entonces debería "reinterrumpirse" con el siguiente encantamiento:

Thread.currentThread().interrupt();

Esto asegura que el subproceso volverá a subir la excepción interrumpida tan pronto como sea posible.

Bert F
fuente
2

Lo consideraría una mala práctica o al menos un poco arriesgado. Por lo general, los métodos de nivel superior no realizan operaciones de bloqueo y nunca veránInterruptedException allí. Si lo enmascara en cada lugar donde realiza una operación interrumpible, nunca lo obtendrá.

La única razón para Thread.currentThread.interrupt()no generar ninguna otra excepción o solicitud de interrupción de señalización de ninguna otra manera (por ejemplo, establecer interruptedla variable de variable local en el bucle principal de un hilo) es la situación en la que realmente no puede hacer nada con la excepción, como en los finallybloques.

Vea la respuesta de Péter Török, si desea comprender mejor las implicaciones de la Thread.currentThread.interrupt()llamada.

Piotr Findeisen
fuente
0

Referir de java doc

Si este hilo está bloqueado en una invocación de wait (), join (), sleep (long), su estado de interrupción se borrará y recibirá una excepción interrumpida.

Si este hilo está bloqueado en una operación de E / S, se establecerá el estado de interrupción del hilo y el hilo recibirá una ClosedByInterruptException.

Si este subproceso está bloqueado en un selector, se establecerá el estado de interrupción del subproceso y volverá inmediatamente de la operación de selección.

Si ninguna de las condiciones anteriores se cumple, se establecerá el estado de interrupción de este hilo.

Por lo tanto, si cambia el método sleepBabySleep () en @Ajay George Answer a la operación de E / S o simplemente un sysout, no tiene que volver a configurar el estado para detener el programa. (Por cierto, ni siquiera lanzan InterruptedException)

Al igual que @ Péter Török dijo => Esto se hace para mantener el estado. (Y en particular para el método que arrojará InterruptedException)

Michael Ouyang
fuente