¿Cómo matas a un java.lang.Thread
en Java?
ExecutorStatus
a esta pregunta: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
¿Cómo matas a un java.lang.Thread
en Java?
ExecutorStatus
a esta pregunta: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Respuestas:
Vea este hilo de Sun sobre por qué se desaprobaronThread.stop()
. Entra en detalles sobre por qué este era un mal método y qué se debe hacer para detener los subprocesos de forma segura en general.
La forma en que recomiendan es usar una variable compartida como un indicador que le pide al hilo de fondo que se detenga. Esta variable puede ser establecida por un objeto diferente que solicita la terminación del hilo.
getConnection()
de java.sql.DriverManager
. Si el intento de conexión tarda demasiado, trato de eliminar el hilo correspondiente llamando Thread.interrupt()
pero no influye en el hilo en absoluto. Sin Thread.stop()
embargo, funciona, aunque Oracle dice que no debería funcionar si interrupt()
no funciona. Me pregunto cómo hacerlo funcionar y evitar el uso de métodos obsoletos.
Generalmente no lo haces ..
Le pide que interrumpa lo que sea que esté haciendo usando Thread.interrupt () (enlace javadoc)
Una buena explicación de por qué está en el javadoc aquí (enlace de nota técnica de Java)
interrupt()
se llama al método? La pregunta principal está relacionada con la generación de registros para cada nuevo hilo.
En Java, los subprocesos no se eliminan, pero la detención de un subproceso se realiza de forma cooperativa . Se le pide al hilo que termine y el hilo puede cerrarse con gracia.
A menudo volatile boolean
se usa un campo que el subproceso comprueba y termina periódicamente cuando se establece en el valor correspondiente.
Yo no me utilizar una boolean
para comprobar si el hilo debe terminar . Si lo usa volatile
como un modificador de campo, esto funcionará de manera confiable, pero si su código se vuelve más complejo, ya que en su lugar usa otros métodos de bloqueo dentro del while
ciclo, podría suceder que su código no termine en absoluto o al menos tarde más tiempo . podria querer.
Ciertos métodos de biblioteca de bloqueo admiten interrupción.
Cada hilo ya tiene un estado de interrupción de bandera booleana y debe usarlo. Se puede implementar así:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Código fuente adaptado de Java Concurrency in Practice . Como el cancel()
método es público, puede dejar que otro hilo invoque este método como lo desee.
Una forma es establecer una variable de clase y usarla como centinela.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Establezca una variable de clase externa, es decir, flag = true en el ejemplo anterior. Póngalo en falso para 'matar' el hilo.
volatile
para asegurarse de que funciona correctamente en todas partes. La clase interna no es estática, por lo que el indicador debería ser una variable de instancia. El indicador debe borrarse en un método de acceso para que se puedan realizar otras operaciones (como la interrupción). El nombre "bandera" no es descriptivo.
Hay una manera de cómo puedes hacerlo. Pero si tuvieras que usarlo, o eres un mal programador o estás usando un código escrito por malos programadores. Por lo tanto, debe pensar en dejar de ser un mal programador o dejar de usar este código incorrecto. Esta solución es solo para situaciones en las que NO HAY OTRA MANERA.
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
incluso si está en desuso.
Thread.stop
hace lo mismo pero también verifica el acceso y los permisos. El uso Thread.stop
es bastante obvio, y no recuerdo la razón por la que lo usé en Thread.stop0
lugar de eso. Quizás Thread.stop
no funcionó para mi caso especial (Weblogic en Java 6). O tal vez porque Thread.stop
está en desuso y causa advertencia.
Quiero agregar varias observaciones, basadas en los comentarios que se han acumulado.
Thread.stop()
detendrá un hilo si el administrador de seguridad lo permite.Thread.stop()
es peligroso. Dicho esto, si está trabajando en un entorno JEE y no tiene control sobre el código que se llama, puede ser necesario; ver ¿Por qué Thread.stop está en desuso?stop()
crea un nuevo ThreadDeathError
error en el hilo de llamada y luego arroja ese error en el hilo de destino . Por lo tanto, el seguimiento de la pila generalmente no tiene valor.stop()
verifica con el administrador de seguridad y luego llama a stop1()
esas llamadas stop0()
. stop0()
es código nativoThread.stop()
no se ha eliminado (todavía), pero Thread.stop(Throwable)
se eliminó en Java 11. ( lista de correo , JDK-8204243 )Votaría para Thread.stop()
.
Por ejemplo, tiene una operación duradera (como una solicitud de red). Supuestamente está esperando una respuesta, pero puede llevar tiempo y el usuario navegó a otra interfaz de usuario. Este hilo de espera ahora es a) inútil b) problema potencial porque cuando obtendrá el resultado, es completamente inútil y desencadenará devoluciones de llamada que pueden conducir a varios errores.
Todo eso y puede hacer un procesamiento de respuesta que podría ser intenso en la CPU. Y usted, como desarrollador, ni siquiera puede detenerlo, porque no puede lanzar if (Thread.currentThread().isInterrupted())
líneas en todo el código.
Entonces, la incapacidad de detener con fuerza un hilo es extraño.
Thread.stop()
forma segura de todos modos. No está votando Thread.stop()
, está pidiendo a cada persona que implemente cada operación que pueda tomar mucho tiempo para que sea abortable de forma segura. Y eso puede ser una buena idea, pero no tiene nada que ver con la implementación Thread.stop()
como la forma de solicitar el aborto seguro. Ya tenemos interrupt
para eso.
stop
.
La pregunta es bastante vaga. Si quisiste decir "¿cómo escribo un programa para que un hilo deje de ejecutarse cuando lo quiero?", Entonces otras respuestas deberían ser útiles. Pero si quiso decir "Tengo una emergencia con un servidor que no puedo reiniciar en este momento y solo necesito un subproceso particular para morir, pase lo que pase", entonces necesita una herramienta de intervención para que coincida con las herramientas de monitoreo como jstack
.
Para este propósito creé jkillthread . Consulte sus instrucciones de uso.
Por supuesto, existe el caso en el que está ejecutando algún tipo de código no completamente confiable. (Personalmente, tengo esto al permitir que las secuencias de comandos cargadas se ejecuten en mi entorno Java. Sí, hay una alarma de seguridad sonando en todas partes, pero es parte de la aplicación). respetar algún tipo de señal booleana de ejecución / no ejecución. Su único seguro decente es llamar al método de detención en el hilo si, por ejemplo, se ejecuta más de un tiempo de espera.
Pero, esto es simplemente "decente", y no absoluto, porque el código podría detectar el error ThreadDeath (o cualquier excepción que arrojes explícitamente), y no volver a lanzarlo como se supone que debe hacer un hilo caballeroso. Por lo tanto, la conclusión es AFAIA, no hay seguridad absoluta a prueba de fallas.
No hay forma de matar con gracia un hilo.
Puede intentar interrumpir el hilo, una estrategia común es usar una píldora venenosa para enviar un mensaje al hilo para que se detenga
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
Por lo general, no mata, detiene ni interrumpe un hilo (ni verifica si está interrumpido ()), sino que deja que termine naturalmente.
Es simple. Puede usar cualquier bucle junto con la variable booleana (volátil) dentro del método run () para controlar la actividad del hilo. También puede volver del hilo activo al hilo principal para detenerlo.
De esta manera matas con gracia un hilo :).
Los intentos de terminación abrupta de hilos son malas prácticas de programación bien conocidas y evidencia de un diseño deficiente de la aplicación. Todos los subprocesos de la aplicación multiproceso comparten de manera explícita e implícita el mismo estado del proceso y se ven obligados a cooperar entre sí para mantenerlo consistente, de lo contrario, su aplicación será propensa a los errores que serán realmente difíciles de diagnosticar. Por lo tanto, es responsabilidad del desarrollador proporcionar una garantía de dicha coherencia mediante un diseño de aplicación cuidadoso y claro.
Hay dos soluciones correctas principales para las terminaciones de subprocesos controlados:
Aquí se puede encontrar una explicación buena y detallada de los problemas relacionados con la terminación abrupta de subprocesos, así como ejemplos de soluciones incorrectas y correctas para la terminación de subprocesos controlados:
Aquí hay un par de buenas lecturas sobre el tema:
No conseguí que la interrupción funcionara en Android, así que utilicé este método, funciona perfectamente:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
'Matar un hilo' no es la frase correcta para usar. Aquí hay una forma en que podemos implementar la finalización / salida elegante del hilo en will:
Runnable que utilicé:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
La clase desencadenante:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop está en desuso, entonces, ¿cómo detenemos un hilo en Java?
Siempre use el método de interrupción y el futuro para solicitar la cancelación
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}