Manejo de InterruptedException en Java


¿Cuál es la diferencia entre las siguientes formas de manejo InterruptedException? ¿Cuál es la mejor manera de hacerlo?

try{
 //...
} catch(InterruptedException e) { 
   Thread.currentThread().interrupt(); 
}

O

try{
 //...
} catch(InterruptedException e) {
   throw new RuntimeException(e);
}

EDITAR: También me gustaría saber en qué escenarios se utilizan estos dos.

Author: Nathan Hughes, 2010-10-20

7 answers

Probablemente hayas venido a hacer esta pregunta porque has llamado a un método que arroja InterruptedException.

En primer lugar, debe ver throws InterruptedException para lo que es: Una parte de la firma del método y un posible resultado de llamar al método que está llamando. Así que comience por abrazar el hecho de que un InterruptedException es un resultado perfectamente válido de la llamada al método.

Ahora, si el método al que estás llamando lanza tal excepción, ¿qué debería hacer tu método? Usted puede averiguar la respuesta por pensando en lo siguiente:

¿Tiene sentido para el método que está implementando para lanzar un InterruptedException? Dicho de otra manera, es un InterruptedExceptionun resultado sensato cuando se llama su método?

  • Si , entonces throws InterruptedException debería ser parte de la firma de su método, y debería dejar que la excepción se propague (es decir, no la atrape en absoluto).

    Ejemplo : Su método espera un valor del red para finalizar el cálculo y devolver un resultado. Si la llamada de red de bloqueo lanza un InterruptedException su método no puede terminar el cálculo de una manera normal. Dejas que el InterruptedException se propague.

    int computeSum(Server server) throws InterruptedException {
        // Any InterruptedException thrown below is propagated
        int a = server.getValueA();
        int b = server.getValueB();
        return a + b;
    }
    
  • Si no, entonces usted no debe declarar su método con throws InterruptedException y debe (debe!) captura la excepción. Ahora, dos cosas son importantes a tener en cuenta en esta situación:

    1. Alguien interrumpió tu hilo. Que alguien probablemente esté ansioso por cancelar la operación, terminar el programa con gracia, o lo que sea. Usted debe ser educado con esa persona y volver de su método sin más preámbulos.

    2. A pesar de que su método puede lograr producir un valor de retorno sensible en caso de un InterruptedException, el hecho de que el hilo haya sido interrumpido puede ser importante. En particular, el código que llama a su método puede estar interesado en si se produjo una interrupción durante la ejecución de su método. Usted por lo tanto, debe registrar el hecho de que se haya producido una interrupción configurando el indicador interrumpido: Thread.currentThread().interrupt()

    Ejemplo : El usuario ha pedido imprimir a la suma de dos valores. Imprimir "Failed to compute sum " es aceptable si la suma no se puede calcular (y mucho mejor que dejar que el programa se bloquee con un seguimiento de pila debido a un InterruptedException). En otras palabras, no tiene sentido declarar este método con throws InterruptedException.

    void printSum(Server server) {
         try {
             int sum = computeSum(server);
             System.out.println("Sum: " + sum);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();  // set interrupt flag
             System.out.println("Failed to compute sum");
         }
    }
    

Por ahora debería ser claro que solo hacer throw new RuntimeException(e) es una mala idea. No es muy educado con la persona que llama. Podrías inventar una nueva excepción de tiempo de ejecución, pero la causa raíz (alguien quiere que el hilo detenga la ejecución) podría perderse.

Otros ejemplos:

Aplicación Runnable: Como habrás descubierto, la firma de Runnable.run no permite repensar InterruptedExceptions. Así, que firmado en la implementación de Runnable, lo que significa que que firmado para tratar con los posible InterruptedExceptions. Elija una interfaz diferente, como Callable, o siga el segundo enfoque anterior.

 

Llamando Thread.sleep: Está intentando leer un archivo y la especificación dice que debe intentarlo 10 veces con 1 segundo en el medio. Llama Thread.sleep(1000). Por lo tanto, es necesario tratar con InterruptedException. Para un método como tryToReadFile tiene perfecto sentido decir, " Si me interrumpen, no puedo completar mi acción de tratar de leer el file " . En otras palabras, tiene perfecto sentido para el método lanzar InterruptedExceptions.

String tryToReadFile(File f) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        if (f.exists())
            return readFile(f);
        Thread.sleep(1000);
    }
    return null;
}

Este post ha sido reescrito como un artículo aquí.

 298
Author: aioobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-28 12:23:39

Sucede que estaba leyendo sobre esto esta mañana en mi camino a trabajar en Java Concurrency In Practice por Brian Goetz. Básicamente dice que debes hacer una de dos cosas

  1. Propagar el InterruptedException - Declare su método para lanzar el InterruptedException marcado para que su llamante tenga que lidiar con él.

  2. Restaura la interrupción - A veces no puedes lanzar InterruptedException. En estos casos se debe coger el InterruptedException y restaurar la interrupción estado llamando al método interrupt() en el currentThread para que el código más alto de la pila de llamadas pueda ver que se emitió una interrupción.

 73
Author: mR_fr0g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-24 13:04:54

¿Qué estás tratando de hacer?

El InterruptedException se lanza cuando un hilo está esperando o durmiendo y otro hilo lo interrumpe usando el método interrupt en la clase Thread. Así que si coges esta excepción, significa que el hilo ha sido interrumpido. Por lo general, no tiene sentido llamar a Thread.currentThread().interrupt(); de nuevo, a menos que desee verificar el estado "interrumpido" del subproceso desde otro lugar.

Con respecto a su otra opción de lanzar un RuntimeException, no parece una cosa muy sabia que hacer (¿quién lo hará coger esto? ¿cómo se manejan?), pero es difícil decir más sin información adicional.

 16
Author: Grodriguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-20 09:30:24

Para mí, la clave de esto es: una excepción interrumpida no es nada que salga mal, es el hilo haciendo lo que le dijiste que hiciera. Por lo tanto, replantearlo envuelto en una excepción RuntimeException no tiene sentido.

En muchos casos tiene sentido repensar una excepción envuelta en una excepción de RuntimeException cuando dices, No se lo que salió mal aquí y no puedo hacer nada para arreglarlo, solo quiero que salga del flujo de procesamiento actual y golpee cualquier excepción de toda la aplicación manejador que tengo para que pueda registrarlo. Ese no es el caso con una InterrumpedException, es solo el hilo que responde a tener interrupt() llamado en él, está lanzando la InterrumpedException con el fin de ayudar a cancelar el procesamiento del hilo de una manera oportuna.

Así que propaga la excepción interrumpida, o cómela inteligentemente (es decir, en un lugar donde habrá logrado lo que estaba destinado a hacer) y restablece la bandera de interrupción. Tenga en cuenta que el indicador de interrupción se borra cuando el InterrumpedException se lanza; la suposición que hacen los desarrolladores de la biblioteca Jdk es que capturar la excepción equivale a manejarla, por lo que por defecto el indicador se borra.

Así que definitivamente la primera forma es mejor, el segundo ejemplo publicado en la pregunta no es útil a menos que no esperes que el hilo realmente se interrumpa, y interrumpirlo equivale a un error.

He aquí una respuesta que escribí describiendo cómo funcionan las interrupciones, con un ejemplo. Se puede ver en el código de ejemplo donde está usando la excepción interrumpida para salir de un bucle while en el método run del ejecutable.

 11
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:40

La opción predeterminada correcta es agregar Interrumpidoexcepción a su lista de lanzamientos. Una interrupción indica que otro hilo desea que su hilo termine. La razón de esta solicitud no se hace evidente y es completamente contextual, por lo que si no tiene ningún conocimiento adicional, debe asumir que es solo un apagado amigable, y cualquier cosa que evite ese apagado es una respuesta no amigable.

Java no lanzará aleatoriamente InterrumpedException, todos los consejos no afectarán su aplicación, pero me he topado con un caso en el que el desarrollador sigue la estrategia de "tragar" se convirtió en muy inconveniente. Un equipo había desarrollado un gran conjunto de pruebas y utilizado hilo.Duerme mucho. Ahora empezamos a ejecutar las pruebas en nuestro servidor de CI, y a veces debido a defectos en el código se quedaba atascado en esperas permanentes. Para empeorar la situación, al intentar cancelar el trabajo de CI nunca se cerró porque el Hilo.La interrupción que tenía la intención de abortar la prueba no abortó el trabajo. Teníamos para iniciar sesión en la caja y matar manualmente los procesos.

En resumen, si simplemente lanzas la excepción interrumpida, estás coincidiendo con la intent predeterminada que debe finalizar tu subproceso. Si no puedes agregar InterrumpedException a tu lista de lanzamientos, lo envolvería en una RuntimeException.

No es un argumento racional que InterruptedException debe ser una RuntimeException sí mismo, puesto que fomentaría una mejor "default" de la manipulación. No es una excepción de RuntimeException solo porque los diseñadores se adhirieron a una regla categórica de que una excepción de RuntimeException debería representar un error en el código. Dado que una excepción interrumpida no surge directamente de un error en su código, no lo es. Pero la realidad es que a menudo surge una excepción interrumpida porque hay un error en su código, (es decir, bucle sin fin, dead-lock), y la Interrupción es el método de algún otro hilo para lidiar con ese error.

Si sabes que hay que hacer una limpieza racional, entonces hazlo. Si conoce una causa más profunda para la Interrupción, puede asumir un manejo más integral.

Así que en resumen sus opciones para el manejo deben seguir esta lista:

  1. De forma predeterminada, agregue a los lanzamientos.
  2. Si no se le permite agregar a los lanzamientos, lance RuntimeException(e). (Mejor opción de múltiples malas opciones)
  3. Solo cuando conozca una causa explícita de la Interrupción, maneje como desee. Si su manejo es local a su método, a continuación, restablecer interrumpido por una llamada para Enhebrar.currentThread().interrumpir().
 6
Author: nedruod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 21:32:50

Solo quería agregar una última opción a lo que la mayoría de las personas y artículos mencionan. Como mR_fr0g ha dicho, es importante manejar la interrupción correctamente ya sea por:

  • Propagando la InterruptException

  • Restaurar el estado de interrupción en el hilo

O adicionalmente:

  • Manejo personalizado de la interrupción

No hay nada malo en manejar la interrupción de una manera personalizada dependiendo de sus circunstancias. Como una interrupción es una solicitud de terminación, a diferencia de un comando contundente, es perfectamente válido completar el trabajo adicional para permitir que la aplicación maneje la solicitud con gracia. Por ejemplo, si un hilo está Durmiendo, esperando en IO o una respuesta de hardware, cuando recibe la Interrupción, entonces es perfectamente válido cerrar correctamente cualquier conexión antes de terminar el hilo.

Recomiendo encarecidamente entender el tema, pero este artículo es una buena fuente de información: http://www.ibm.com/developerworks/java/library/j-jtp05236 /

 1
Author: TheIT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-17 02:38:10

Yo diría que en algunos casos está bien no hacer nada. Probablemente no es algo que deberías estar haciendo por defecto, pero en caso de que no haya forma de que ocurra la interrupción, no estoy seguro de qué más hacer (probablemente error de registro, pero eso no afecta el flujo del programa).

Un caso sería en caso de que tenga una cola de tareas (bloqueo). En caso de que tenga un subproceso de demonio manejando estas tareas y no interrumpa el Subproceso por sí mismo (que yo sepa, la jvm no interrumpe el demonio threads on jvm shutdown), no veo manera de que la interrupción suceda, y por lo tanto podría ser ignorada. (Sé que un hilo daemon puede ser asesinado por la jvm en cualquier momento y por lo tanto no es adecuado en algunos casos).

EDITAR: Otro caso podría ser bloques protegidos, al menos basado en el tutorial de Oracle en: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

 0
Author: Bjarne Boström,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 14:11:42