¿Quién llama al método Java Thread interrupt () si yo no?

87

He leído y releído Java Concurrency in Practice, he leído varios hilos aquí sobre el tema, he leído el artículo de IBM Dealing with InterruptedException y, sin embargo, hay algo que simplemente no estoy entendiendo y que creo que se puede romper en dos preguntas:

  1. Si nunca estoy interrumpiendo otros hilos yo mismo, ¿qué puede desencadenar una InterruptedException ?

  2. Si nunca interrumpo otros subprocesos yo mismo usando interrupt () (digamos porque estoy usando otros medios para cancelar mis subprocesos de trabajo, como píldoras de veneno y while (! Cancelado) bucle de estilo [como ambos explicados en JCIP]), ¿qué ¿ Qué significa entonces una InterruptedException ? ¿Qué se supone que debo hacer al atrapar uno? ¿Apagar mi aplicación?

Sintaxis T3rr0r
fuente

Respuestas:

50

El mecanismo de interrupción de subprocesos es la forma preferida de conseguir que un subproceso (cooperante) responda a una solicitud para detener lo que está haciendo. Cualquier hilo (incluido el hilo en sí, creo) podría llamar interrupt()a un hilo.

En la práctica, los casos de uso normales interrupt()involucran algún tipo de marco o administrador que le dice a algún hilo de trabajo que detenga lo que están haciendo. Si el hilo de trabajo es "consciente de la interrupción", notará que ha sido interrumpido a través de una excepción, o verificando periódicamente su indicador de interrupción. Al darse cuenta de que ha sido interrumpido, un hilo de buen comportamiento abandonará lo que está haciendo y se acabará.

Suponiendo el caso de uso anterior, es probable que su código se interrumpa si se ejecuta dentro de un marco de Java o desde algún hilo de trabajo. Y cuando se interrumpe, su código debe abandonar lo que está haciendo y provocar su finalización por los medios más adecuados. Dependiendo de cómo se haya llamado su código, esto podría hacerse regresando o lanzando alguna excepción apropiada. Pero probablemente no debería llamar System.exit(). (Su aplicación no necesariamente sabe por qué fue interrumpida, y ciertamente no sabe si hay otros subprocesos que deben ser interrumpidos por el marco).

Por otro lado, si su código no está diseñado para ejecutarse bajo el control de algún marco, podría argumentar que InterruptedExceptiones una excepción inesperada; es decir, un error. En ese caso, debe tratar la excepción como lo haría con otros errores; por ejemplo, envuélvalo en una excepción sin marcar, y captúrelo y regístrelo en el mismo punto en el que trata con otras excepciones inesperadas sin marcar. (Alternativamente, su aplicación podría simplemente ignorar la interrupción y continuar haciendo lo que estaba haciendo).


1) Si nunca estoy interrumpiendo otros hilos, ¿qué puede desencadenar una InterruptedException?

Un ejemplo es si sus Runnableobjetos se ejecutan usando un ExecutorServicey shutdownNow()se llama en el servicio. Y, en teoría, cualquier grupo de subprocesos de terceros o marco de gestión de subprocesos podría hacer legítimamente algo como esto.

2) Si nunca voy a interrumpir otros hilos usando interrupt () ... ¿qué significa InterruptedExceptionentonces? ¿Qué se supone que debo hacer al atrapar uno? ¿Apagar mi aplicación?

Necesita analizar la base de código para averiguar qué está haciendo las interrupt()llamadas y por qué. Una vez que se haya dado cuenta de eso, puede averiguar qué >> debe hacer su << parte de la aplicación.

Hasta que sepa por qué InterruptedExceptionse está lanzando, le aconsejaría tratarlo como un error grave; por ejemplo, imprima un seguimiento de pila en el archivo de registro y cierre la aplicación. (Obviamente, esa no siempre es la respuesta correcta ... pero el punto es que esto es "un error", y debe notificarse al desarrollador / mantenedor).

3) ¿Cómo puedo saber quién / qué está llamando interrupt()?

No hay una buena respuesta a esto. Lo mejor que puedo sugerir es establecer un punto de interrupción en el Thread.interrupt()y mirar la pila de llamadas.

Esteban C
fuente
12

Si decide integrar su código con otras bibliotecas, pueden llamar interrupt()a su código. por ejemplo, si decide en el futuro ejecutar su código dentro de un ExecutorService , entonces eso puede forzar un cierre a través de interrupt().

Para decirlo brevemente, consideraría no solo dónde se está ejecutando su código ahora , sino en qué contexto se puede ejecutar en el futuro. por ejemplo, ¿lo vas a poner en una biblioteca? Un contenedor ? ¿Cómo lo usarán otras personas? ¿Lo vas a reutilizar?

Brian Agnew
fuente
Pensé que solo shutdownNow llama al método interrupt (). ¿También es cierto para el apagado?
Harinder
9

Como han señalado otros, interrumpir un hilo (en realidad, interrumpir una llamada de bloqueo) generalmente se usa con el propósito de salir limpiamente o cancelar una actividad en curso.

Sin embargo, no debe tratar un InterruptedExceptionsolo como un "comando de salida". En cambio, debe pensar en las interrupciones como un medio para controlar el estado de ejecución de los subprocesos, de la misma manera que lo Object.notify()hace. De la misma manera que verificaría el estado actual después de despertarse de una llamada a Object.wait()(no asume que el despertador significa que su condición de espera se ha cumplido), después de recibir un empujón con una interrupción, debe verificar por qué fue interrumpido . Generalmente hay una forma de hacer esto. Por ejemplo, java.util.concurrent.FutureTasktiene un isCancelled()método.

Muestra de código:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}
Øyvind Bakksjø
fuente
3

El problema con la pregunta es "yo". "Yo" generalmente se refiere a una sola instancia de una clase. Quiero decir con eso, que cualquier pieza particular de código de bajo nivel (clase) no debería depender de la implementación de todo el sistema. Habiendo dicho eso, debe tomar algunas decisiones "arquitectónicas" (como en qué plataforma ejecutar).

Las posibles interrupciones inesperadas provenientes del JRE son tareas canceladas java.util.concurrenty cierres de subprogramas.

El manejo de interrupciones de subprocesos generalmente se escribe incorrectamente. Por lo tanto, sugiero la decisión arquitectónica para evitar causar interrupciones cuando sea posible. Sin embargo, las interrupciones de manejo de código siempre deben escribirse correctamente. No puedo eliminar las interrupciones de la plataforma ahora.

Tom Hawtin - tackline
fuente
Hola Tom, recuerdo tu nombre de cljp;) Bueno, precisamente: nunca tuve que lanzar interrupt () yo mismo ... A menos que esté detectando una InterruptedException y necesite reafirmar el estado interrumpido, pero esto todavía no es del 100% claro para mi. Soy nuevo aquí y me sorprende la cantidad de votos a favor y respuestas / comentarios (tanto los correctos como los incorrectos): obviamente es un tema que no es trivial o, al menos, no suele estar bien explicado. Dicho esto, gracias a todas las publicaciones, estoy empezando a tener una imagen más clara de lo que está sucediendo :)
SyntaxT3rr0r
3

Puede aprender esto creando su propia clase de subproceso (extensión java.lang.Thread) y interrupt()método de anulación , en el que registra el seguimiento de la pila en, digamos, un campo String, y luego lo transfiere a super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}
fines de semana
fuente
1

Como ya se mencionó, otra biblioteca puede interrumpir sus hilos. Incluso si la biblioteca no tiene acceso explícito a los subprocesos de su código, aún pueden obtener la lista de subprocesos que se están ejecutando e interrumpirlos de esa manera con el siguiente método .

mango borracho
fuente
1

Creo que entiendo por qué estás un poco confundido acerca de la interrupción. Considere mis respuestas en línea:

Si nunca estoy interrumpiendo otros hilos yo mismo, ¿qué puede desencadenar una InterruptedException ?

En primer lugar, puede interrumpir otros hilos; Sé que en JCiP se menciona que nunca debes interrumpir los subprocesos que no te pertenecen; sin embargo, esta declaración debe entenderse correctamente. Lo que significa es que su código, que podría estar ejecutándose en cualquier hilo arbitrario, no debería manejar la interrupción porque, dado que no es el propietario del hilo, no tiene ni idea de su política de interrupción. Por lo tanto, puede solicitar la interrupción en otros hilos, pero deje que su propietario tome el curso de la acción de interrupción; tiene encapsulada la política de interrupción, no su código de tarea; ¡al menos sea cortés para poner la bandera de interrupción!

Hay muchas formas por las que aún podría haber interrupciones, pueden haber tiempos de espera, interrupciones de JVM, etc.

Si nunca interrumpo otros subprocesos yo mismo usando interrupt () (digamos porque estoy usando otros medios para cancelar mis subprocesos de trabajo, como píldoras de veneno y while (! Cancelado) bucle de estilo [como ambos explicados en JCIP]), ¿qué ¿Qué significa entonces una InterruptedException? ¿Qué se supone que debo hacer al atrapar uno? ¿Apagar mi aplicación?

Debe tener mucho cuidado aquí; Si posee el hilo que lanzó InterruptedException (IE), entonces sabe qué hacer al detectarlo, digamos que puede cerrar su aplicación / servicio o puede reemplazar este hilo muerto por uno nuevo. Sin embargo, si no posee el hilo, al capturar IE, vuelva a lanzarlo más arriba en la pila de llamadas o después de hacer algo (puede estar registrando), restablezca el estado interrumpido para que el código que posee este hilo, cuando el control lo alcance, pueda aprender que el hilo fue interrumpido y, por lo tanto, tomar las medidas necesarias, ya que solo él conoce la política de interrupción.

Espero que esto haya ayudado.

nawazish-stackoverflow
fuente
0

El InterruptedExceptiondice que una rutina puede ser interrumpido, pero no necesariamente que sea.

Si no espera la interrupción, debe tratarla como lo haría con cualquier otra excepción inesperada. Si se encuentra en una sección crítica donde una excepción inesperada podría tener consecuencias atroces, podría ser mejor intentar limpiar los recursos y cerrar con elegancia (porque obtener las señales de interrupción indica que se está utilizando una aplicación bien diseñada que no depende de interrupciones de alguna manera no fue diseñado, por lo que debe haber algo mal). Alternativamente, si el código en cuestión es algo no crítico o trivial, es posible que desee ignorar (o registrar) la interrupción y continuar.

Ceniza
fuente