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.
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 InterruptedException
un resultado sensato cuando se llama su método?
-
Si sí, 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 elInterruptedException
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: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.
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 unInterruptedException
). En otras palabras, no tiene sentido declarar este método conthrows 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 deRunnable.run
no permite repensarInterruptedExceptions
. Así, que firmado en la implementación deRunnable
, lo que significa que que firmado para tratar con los posibleInterruptedExceptions
. Elija una interfaz diferente, comoCallable
, 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. LlamaThread.sleep(1000)
. Por lo tanto, es necesario tratar conInterruptedException
. Para un método comotryToReadFile
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 lanzarInterruptedExceptions
.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í.
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
Propagar el
InterruptedException
- Declare su método para lanzar elInterruptedException
marcado para que su llamante tenga que lidiar con él.Restaura la interrupción - A veces no puedes lanzar
InterruptedException
. En estos casos se debe coger elInterruptedException
y restaurar la interrupción estado llamando al métodointerrupt()
en elcurrentThread
para que el código más alto de la pila de llamadas pueda ver que se emitió una interrupción.
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.
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.
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:
- De forma predeterminada, agregue a los lanzamientos.
- Si no se le permite agregar a los lanzamientos, lance RuntimeException(e). (Mejor opción de múltiples malas opciones)
- 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().
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 /
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
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