Java Language Manipulación InterruptedException


Ejemplo

InterruptedException es una bestia confusa: aparece en métodos aparentemente inocuos como Thread.sleep() , pero su manejo incorrecto conduce a un código difícil de administrar que se comporta mal en entornos concurrentes.

En su forma más básica, si se Thread.interrupt() una InterruptedException , significa alguien, en algún lugar, llamado Thread.interrupt() en el hilo en el que se está ejecutando su código. Es posible que esté inclinado a decir "¡Es mi código! ¡Nunca lo interrumpiré! " y por lo tanto hacer algo como esto:

// Bad. Don't do this.
try {
  Thread.sleep(1000);
} catch (InterruptedException e) {
  // disregard
}

Pero esta es exactamente la manera incorrecta de manejar un evento "imposible" que ocurre. Si sabe que su aplicación nunca encontrará una InterruptedException , debe tratar dicho evento como una violación grave de las suposiciones de su programa y salir lo más rápido posible.

La forma correcta de manejar una interrupción "imposible" es así:

// When nothing will interrupt your code
try {
  Thread.sleep(1000);
} catch (InterruptedException e) {
  Thread.currentThread().interrupt();
  throw new AssertionError(e);
}

Esto hace dos cosas; primero restaura el estado de interrupción del hilo (como si la InterruptedException no se hubiera lanzado en primer lugar), y luego lanza un AssertionError indica que se han violado los invariantes básicos de su aplicación. Si sabe con certeza que nunca interrumpirá el hilo en el que se ejecuta este código es seguro, ya que nunca debe catch bloque catch .

El uso de la clase Uninterruptibles de Guava ayuda a simplificar este patrón; llamando a Uninterruptibles.sleepUninterruptibly() ignora el estado interrumpido de un hilo hasta que la duración del tiempo de espera (en ese momento se restaura para las llamadas posteriores para inspeccionar y lanzar su propia InterruptedException ). Si sabe que nunca interrumpirá dicho código, esto evita con seguridad la necesidad de ajustar sus llamadas de reposo en un bloque try-catch.

Más a menudo, sin embargo, no puede garantizar que su hilo nunca será interrumpido. En particular, si está escribiendo un código que será ejecutado por un Executor o algún otro administrador de subprocesos, es fundamental que su código responda rápidamente a las interrupciones, de lo contrario su aplicación se atascará o incluso se interrumpirá.

En tales casos, lo mejor es generalmente permitir que la InterruptedException propague por la pila de llamadas, agregando una throws InterruptedException a cada método. Esto puede parecer un poco confuso, pero en realidad es una propiedad deseable: las firmas de su método ahora indican a las personas que llaman que responderá rápidamente a las interrupciones.

// Let the caller determine how to handle the interrupt if you're unsure
public void myLongRunningMethod() throws InterruptedException {
  ...
}

En casos limitados (p. Ej., Al anular un método que no throw ninguna excepción comprobada), puede restablecer el estado interrumpido sin generar una excepción, esperando que se ejecute cualquier código al lado para manejar la interrupción. Esto retrasa el manejo de la interrupción pero no la suprime por completo.

// Suppresses the exception but resets the interrupted state letting later code
// detect the interrupt and handle it properly.
try {
  Thread.sleep(1000);
} catch (InterruptedException e) {
  Thread.currentThread().interrupt();
  return ...; // your expectations are still broken at this point - try not to do more work.
}