¿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: Me gustaría saber también en qué escenarios se utilizan estos dos.
Respuestas:
Probablemente has venido a hacer esta pregunta porque has llamado a un método que arroja
InterruptedException
.En primer lugar, debe ver
throws InterruptedException
qué es: una parte de la firma del método y un posible resultado de llamar al método que está llamando. Comience por aceptar el hecho de que anInterruptedException
es un resultado perfectamente válido de la llamada al método.Ahora, si el método que está llamando arroja tal excepción, ¿qué debe hacer su método? Puede encontrar la respuesta pensando en lo siguiente:
¿Tiene sentido para el método que está implementando para lanzar un
InterruptedException
? Dicho de otra manera, ¿es unInterruptedException
resultado razonable al llamar a su método?En caso afirmativo ,
throws InterruptedException
debería ser parte de la firma de su método, y debería permitir que la excepción se propague (es decir, no la capte en absoluto).Si no , entonces no debe declarar su método
throws InterruptedException
y debe (¡debe!) Atrapar 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, finalizar el programa con gracia o lo que sea. Debe ser cortés con esa persona y regresar de su método sin más preámbulos.
Aunque su método puede lograr producir un valor de retorno razonable en caso de
InterruptedException
que el hilo se haya interrumpido, aún puede ser importante. En particular, el código que llama a su método puede estar interesado en saber si se produjo una interrupción durante la ejecución de su método. Por lo tanto, debe registrar el hecho de que se produjo una interrupción configurando el indicador interrumpido:Thread.currentThread().interrupt()
A estas alturas debería estar claro que solo hacer
throw new RuntimeException(e)
es una mala idea. No es muy amable con la persona que llama. Podría 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:
Esta publicación ha sido reescrita como un artículo aquí .
fuente
interrupt()
para preservar el estado interrumpido. ¿Cuál es la razón detrás de no hacer esto en unThread.sleep()
?Thread.currentThread.interrupt()
a unInterruptedException
bloque catch solo establecerá la bandera de interrupción. No hará que otroInterruptedException
sea arrojado / atrapado en unInterruptedException
bloque de captura externo .Da la casualidad de que estaba leyendo sobre esto esta mañana en mi camino al trabajo en Java Concurrency In Practice de Brian Goetz. Básicamente él dice que deberías hacer una de tres cosas
Propague el
InterruptedException
: declare su método para lanzar el marcadoInterruptedException
para que su interlocutor tenga que lidiar con él.Restaurar la interrupción : a veces no puedes lanzar
InterruptedException
. En estos casos, debe capturarInterruptedException
y restaurar el estado de interrupción llamando alinterrupt()
método en elcurrentThread
para que el código más arriba en la pila de llamadas pueda ver que se emitió una interrupción y regresar rápidamente del método. Nota: esto solo es aplicable cuando su método tiene una semántica de "intento" o "mejor esfuerzo", es decir, nada crítico sucedería si el método no logra su objetivo. Por ejemplo,log()
osendMetric()
puede ser tal método, oboolean tryTransferMoney()
, pero novoid transferMoney()
. Ver aquí para más detalles.Uninterruptibles
.Uninterruptibles
tomar el código repetitivo como en el ejemplo de Tarea no cancelable en JCIP § 7.1.3.fuente
¿Que estás tratando de hacer?
Se
InterruptedException
emite cuando un hilo está esperando o durmiendo y otro hilo lo interrumpe usando elinterrupt
método en claseThread
. Entonces, si detecta esta excepción, significa que el hilo ha sido interrumpido. Por lo general, no tiene sentidoThread.currentThread().interrupt();
volver a llamar , a menos que desee verificar el estado "interrumpido" del hilo desde otro lugar.Con respecto a su otra opción de lanzar un
RuntimeException
, no parece una cosa muy sabia (¿quién atrapará esto? ¿Cómo se manejará?) Pero es difícil decir más sin información adicional.fuente
Thread.currentThread().interrupt()
establece el indicador de interrupción (nuevamente), lo cual es útil de hecho si queremos asegurarnos de que la interrupción se note y se procese en un nivel superior.Para mí, la clave de esto es: una InterruptedException no es que algo salga mal, es el hilo que hace lo que le dijiste que hiciera. Por lo tanto, volver a lanzarlo envuelto en una RuntimeException no tiene sentido.
En muchos casos, tiene sentido volver a lanzar una excepción envuelta en una RuntimeException cuando dice: No sé qué salió mal aquí y no puedo hacer nada para solucionarlo, solo quiero que salga del flujo de procesamiento actual y presione cualquier controlador de excepciones de toda la aplicación que tenga para que pueda registrarlo. Ese no es el caso con una InterruptedException, es solo el hilo que responde a haber llamado a interrupt (), lanza la InterruptedException para ayudar a cancelar el procesamiento del hilo de manera oportuna.
Entonces, propague la InterruptedException, o cómela de manera inteligente (es decir, en un lugar donde habrá logrado lo que estaba destinado a hacer) y restablezca la bandera de interrupción. Tenga en cuenta que el indicador de interrupción se borra cuando se lanza la InterruptedException; la suposición de los desarrolladores de la biblioteca Jdk es que capturar la excepción equivale a manejarla, por lo que, de forma predeterminada, se borra la bandera.
Entonces, definitivamente, la primera forma es mejor, el segundo ejemplo publicado en la pregunta no es útil a menos que no espere que el hilo se interrumpa realmente, e interrumpirlo equivale a un error.
Aquí hay una respuesta que escribí describiendo cómo funcionan las interrupciones, con un ejemplo . Puede ver en el código de ejemplo dónde está usando la InterruptedException para rescatar un ciclo while en el método de ejecución de Runnable.
fuente
La opción predeterminada correcta es agregar InterruptedException a su lista de lanzamientos. Una interrupción indica que otro hilo desea que su hilo termine. El motivo 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 cierre amigable, y cualquier cosa que evite ese cierre es una respuesta no amigable.
Java no lanzará aleatoriamente InterruptedException, todos los consejos no afectarán su aplicación, pero me he encontrado con un caso en el que los desarrolladores que siguen la estrategia de "tragar" se volvieron muy inconvenientes. Un equipo desarrolló un gran conjunto de pruebas y usó Thread.Sleep mucho. Ahora comenzamos a ejecutar las pruebas en nuestro servidor de CI y, a veces, debido a defectos en el código, quedamos atrapados en esperas permanentes. Para empeorar la situación, al intentar cancelar el trabajo de CI nunca se cerró debido a que Thread.Interrupt que estaba destinado a abortar la prueba no abortó el trabajo. Tuvimos que iniciar sesión en el cuadro y eliminar manualmente los procesos.
En resumen, si simplemente lanza la InterruptedException, está haciendo coincidir la intención predeterminada de que su hilo debería terminar. Si no puede agregar InterruptedException a su lista de lanzamiento, lo envolvería en RuntimeException.
Hay un argumento muy racional para hacer que InterruptedException debería ser una RuntimeException en sí misma, ya que eso fomentaría un mejor manejo "predeterminado". No es una RuntimeException solo porque los diseñadores se apegaron a una regla categórica de que una RuntimeException debería representar un error en su 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 InterruptedException porque hay un error en su código (es decir, un bucle sin fin, un punto muerto), y la Interrupción es el método de otro hilo para tratar ese error.
Si sabe que hay que realizar una limpieza racional, hágalo. Si conoce una causa más profunda para la interrupción, puede asumir un manejo más integral.
En resumen, sus opciones de manejo deben seguir esta lista:
fuente
Solo quería agregar una última opción a lo que la mayoría de las personas y artículos mencionan. Como ha declarado mR_fr0g, es importante manejar la interrupción correctamente ya sea:
Propagando la excepción de interrupción
Restaurar estado de interrupción en subproceso
O adicionalmente:
No hay nada de malo en manejar la interrupción de forma personalizada según sus circunstancias. Como una interrupción es una solicitud de terminación, a diferencia de un comando enérgico, es perfectamente válido completar un trabajo adicional para permitir que la aplicación maneje la solicitud con gracia. Por ejemplo, si un subproceso está en espera, esperando una respuesta de E / S o de hardware, cuando recibe la interrupción, entonces es perfectamente válido cerrar con gracia cualquier conexión antes de terminar el subproceso.
Recomiendo encarecidamente comprender el tema, pero este artículo es una buena fuente de información: http://www.ibm.com/developerworks/java/library/j-jtp05236/
fuente
Yo diría que en algunos casos está bien no hacer nada. Probablemente no sea algo que deba hacer de manera predeterminada, pero en caso de que no haya forma de que ocurra la interrupción, no estoy seguro de qué más hacer (probablemente un 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 hilo de demonio manejando estas tareas y no interrumpa el hilo usted mismo (que yo sepa, jvm no interrumpe los hilos de demonio en el apagado de jvm), no veo forma de que ocurra la interrupción, y por lo tanto podría ser solo ignorado (Sí sé que el jvm puede matar un hilo de demonio en cualquier momento y, por lo tanto, no es adecuado en algunos casos).
EDITAR: Otro caso podría ser bloques protegidos, al menos basados en el tutorial de Oracle en: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
fuente