hilos - pause thread java
¿Cómo iniciar/detener/reiniciar un hilo en Java? (10)
A veces, si se inició un Thread
y se cargó una clase dinámica a la baja que está procesando con mucho Thread
/ currentThread
sleep mientras se ignoran capturas interrumpidas Exception
es posible que una interrupción no sea suficiente para salir completamente de la ejecución.
En ese caso, podemos suministrar estas interrupciones basadas en bucle:
while(th.isAlive()){
log.trace("Still processing Internally; Sending Interrupt;");
th.interrupt();
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Me está costando mucho encontrar la manera de iniciar, detener y reiniciar un hilo en Java.
Específicamente, tengo una Task
clase (actualmente implementa Runnable
) en un archivo Task.java
. Mi aplicación principal debe poder INICIAR esta tarea en un hilo, DETENER (matar) el hilo cuando lo necesite y, a veces, MATAR Y REINICIAR el hilo ...
Mi primer intento fue con ExecutorService
pero parece que no puedo encontrar la manera de reiniciar una tarea. Cuando uso .shutdownnow()
cualquier llamada futura a .execute()
falla porque el ExecutorService
está "apagado" ...
Entonces, ¿cómo podría lograr esto?
Como dice Taylor L, no se puede simplemente "detener" un hilo (llamando a un método simple) debido a que podría dejar su sistema en un estado inestable ya que el hilo de llamada externa puede no saber qué está pasando dentro. tu hilo.
Dicho esto, la mejor manera de "detener" un hilo es hacer que el hilo se vigile a sí mismo y que sepa y entienda cuándo debería detenerse.
Es imposible finalizar un hilo a menos que el código que se ejecuta en ese hilo verifique y permita la terminación.
Usted dijo: "Tristemente debo matar / reiniciarlo ... no tengo control total sobre el contenido del hilo y para mi situación requiere un reinicio"
Si el contenido del hilo no permite la terminación de su ejecución, entonces no puede terminar ese hilo.
En tu publicación dijiste: "Mi primer intento fue con ExecutorService, pero parece que no puedo encontrar la manera de reiniciar una tarea. Cuando uso .shutdownnow () ..."
Si nos fijamos en el origen de "shutdownnow", simplemente se ejecuta e interrumpe los hilos actualmente en ejecución. Esto no detendrá su ejecución a menos que el código en esos hilos verifique si ha sido interrumpido y, si es así, detiene la ejecución. Entonces shutdownnow probablemente no está haciendo lo que piensas.
Permítanme ilustrar lo que quiero decir cuando digo que el contenido del hilo debe permitir que termine ese hilo:
myExecutor.execute(new Runnable() {
public void run() {
while (true) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
Ese hilo continuará ejecutándose para siempre, incluso aunque se haya llamado a shutdown, ya que nunca verifica si ha finalizado o no. Este hilo, sin embargo, se cerrará:
myExecutor.execute(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
Dado que este hilo se comprueba para ver si ha sido interrumpido / apagado / terminado.
Entonces, si quieres un hilo que puedas cerrar, debes asegurarte de que verifique si se ha interrumpido. Si desea un hilo que pueda "cerrar" y "reiniciar", puede hacer un ejecutable que pueda tomar nuevas tareas como se mencionó anteriormente.
¿Por qué no puedes cerrar un hilo en funcionamiento? Bueno, de hecho, mentí, puedes llamar a "yourThread.stop ()", pero ¿por qué es una mala idea? El hilo podría estar en una sección sincronizada (u otra sección crítica, pero nos limitaremos a las secciones guardadas por la palabra clave sincrónica aquí) del código cuando lo detenga. se supone que los bloques de sincronización deben ejecutarse en su totalidad y solo en un subproceso antes de ser accedidos por otro subproceso. Si detiene un hilo en el medio de un bloque de sincronización, la protección establecida por el bloque de sincronización se invalidará y su programa entrará en un estado desconocido. Los desarrolladores ponen cosas en bloques de sincronización para mantener las cosas sincronizadas, si usas threadInstance.stop () destruyes el significado de sincronizar, lo que el desarrollador de ese código intentaba lograr y cómo el desarrollador de ese código esperaba que sus bloques sincronizados comportarse.
Estoy completamente en desacuerdo con el reclamo "no se puede ''detener'' un hilo". Es una visión miope sobre un tema espinoso. ¿Por qué?
Controlar regularmente la bandera interrumpida no es más que otra forma de espera ocupada con la difícil decisión de "cuándo verificar la bandera y con qué frecuencia". Puede ser muy feo o imposible de responder. El hilo de la clase también tiene el método "stop (Throwable throwable)", que desafortunadamente ha desaprobado lo que desapruebo profundamente. Dado el método run () con su cuerpo en una declaración try-catch-finally: ¿Por qué está bien que cualquier declaración (desde el interior del cuerpo) pueda arrojar cualquier excepción marcada o no marcada mientras se invoca a stop (nueva MyRuntimeException ()) desde afuera puede no? ¿Es realmente tan inesperado desde fuera? Entonces, ¿qué hay de RuntimeExceptions inesperados que rara vez se detectan ya que a menudo se desconocen? Al final, las cláusulas catch tienen que ver con la excepción, ya sea desde adentro o desde afuera. Y el bloque final puede arreglarse. Espero que la gente piense nuevamente en el tema del diseño.
Creo que un hilo debería poder morir (finalizando por sí solo) o ser eliminado (terminado inmediatamente con una excepción).
Hay una diferencia entre pausar un hilo y detenerlo / matarlo. Si para ti significa matar el hilo, entonces un reinicio simplemente significa crear un nuevo hilo y lanzarlo.
Existen métodos para eliminar hilos de un hilo diferente (por ejemplo, su reproductor), pero en general son inseguros. Podría ser más seguro si su hilo constantemente revisa alguna bandera para ver si debería continuar (supongo que hay algún bucle en su hilo), y hacer que el "controlador" externo cambie el estado de esa bandera.
Puedes ver un poco más en: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
¿Puedo preguntar por qué quieres matar el hilo y reiniciarlo? ¿Por qué no esperar a que se vuelvan a necesitar sus servicios? Java tiene mecanismos de sincronización exactamente para ese propósito. El hilo estará durmiendo hasta que el controlador le notifique que continúe la ejecución.
No puede reiniciar un hilo así que su mejor opción es guardar el estado actual del objeto en el momento en que se detuvo el hilo y cuando las operaciones deben continuar en ese objeto puede recrear ese objeto usando el guardado y luego iniciar el nuevo hilo .
Estos dos artículos Swing Worker and Concurrency pueden ayudarlo a determinar la mejor solución para su problema.
Revise java.lang.Thread
.
Para iniciar o reiniciar (una vez que se detiene un hilo, no puede reiniciar el mismo hilo, pero no importa, simplemente cree una nueva instancia de Thread
):
// Create your Runnable instance
Task task = new Task(...);
// Start a thread and run your Runnable
Thread t = new Thread(task);
Para detenerlo, tenga un método en su instancia de Task
que establezca un indicador para indicarle al método de run
que salga; Al regresar de la run
sale del hilo. Si su código de llamada necesita saber que el hilo realmente se ha detenido antes de que regrese, puede usar join
:
// Tell Task to stop
task.setStopFlag(true);
// Wait for it to do so
t.join();
Respecto al reinicio: aunque no se puede reiniciar un Thread
, puede reutilizar su instancia de Runnable
con un nuevo subproceso si tiene estado y desea conservarlo; eso viene a ser lo mismo Solo asegúrese de que Runnable
esté diseñado para permitir que se run
varias llamadas.
Si su tarea está realizando algún tipo de acción en un bucle, hay una forma de pausar / reiniciar el proceso, pero creo que debería estar fuera de lo que actualmente ofrece la API Thread. Si se trata de un proceso de un solo disparo, no conozco ninguna forma de suspender / reiniciar sin tener que ejecutar una API que ha quedado obsoleta o que ya no está permitida.
En cuanto a los procesos en bucle, la manera más fácil que se me ocurre es que el código que genera la Tarea ejemplifica un ReentrantLock y lo pasa a la tarea, además de mantener una referencia en sí misma. Cada vez que la Tarea ingresa en su ciclo, intenta un bloqueo en la instancia de ReentrantLock y cuando el ciclo finaliza debe desbloquearse. Es posible que desee encapsular todo esto try / finally, asegurándose de soltar el bloqueo al final del ciclo, incluso si se lanza una excepción.
Si desea pausar la tarea simplemente intente un bloqueo desde el código principal (ya que mantuvo una referencia a mano). Lo que esto hará es esperar a que se complete el ciclo y no permitir que comience otra iteración (ya que el hilo principal mantiene un bloqueo). Para reiniciar el hilo simplemente destrabe del código principal, esto permitirá que la tarea reanude sus bucles.
Para detener el hilo de manera permanente, usaría la API normal o dejaría una marca en la Tarea y un colocador para la bandera (algo así como Detener de inmediato). Cuando el bucle encontró un valor verdadero para este indicador, detiene el procesamiento y completa el método de ejecución.
Una vez que se detiene un hilo, no puede reiniciarlo. Sin embargo, no hay nada que te impida crear e iniciar un nuevo hilo.
Opción 1: cree un nuevo hilo en lugar de intentar reiniciarlo.
Opción 2: en lugar de dejar que el hilo se detenga, espere y luego, cuando reciba la notificación, puede permitir que vuelva a funcionar. De esta forma, el hilo nunca se detiene y nunca será necesario reiniciarlo.
Editar basado en el comentario:
Para "matar" el hilo, puede hacer algo como lo siguiente.
yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
You can start a thread like:
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
try {
//Do you task
}catch (Exception ex){
ex.printStackTrace();}
}
});
thread.start();
To stop a Thread:
thread.join();//it will kill you thread
//if you want to know whether your thread is alive or dead you can use
System.out.println("Thread is "+thread.isAlive());
Es aconsejable crear un nuevo hilo en lugar de reiniciarlo.