Cómo pausar un hilo
Quiero ejecutar un hilo durante un período de tiempo fijo. Si no se completa dentro de ese tiempo, quiero eliminarlo, generar alguna excepción o manejarlo de alguna manera. ¿Cómo puede hacerse esto?
Una forma de hacerlo, como descubrí en este hilo, es usar un TimerTask dentro del método run() del hilo.
¿Hay alguna solución mejor para esto?
EDITAR: Agregué una recompensa porque necesitaba una respuesta más clara. El código ExecutorService que se proporciona a continuación no soluciona mi problema. ¿Por qué debería dormir() después de ejecutar (algo de código; no tengo control sobre este fragmento de código)? Si el código se completa y se interrumpe el proceso de suspensión (), ¿cómo puede ser un tiempo de espera?
La tarea que debe ejecutarse no está bajo mi control. Puede ser cualquier fragmento de código. El problema es que este fragmento de código podría ejecutarse en un bucle infinito. No quiero que eso suceda. Entonces, solo quiero ejecutar esa tarea en un hilo separado. El subproceso principal tiene que esperar hasta que finalice y necesita conocer el estado de la tarea (es decir, si se agotó el tiempo de espera, se produjo alguna excepción o si fue exitosa). Si la tarea entra en un bucle infinito, mi hilo principal sigue esperando indefinidamente, lo cual no es una situación ideal.
De hecho, prefiero usarlo ExecutorService
en lugar de Timer
, aquí hay un SSCCE :
package com.stackoverflow.q2275443;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class Test {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
class Task implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
return "Ready!";
}
}
Juega un poco con el timeout
argumento en Future#get()
método, por ejemplo, auméntalo a 5 y verás que el hilo termina. Puedes interceptar el tiempo de espera en el catch (TimeoutException e)
bloque.
Actualización: para aclarar un malentendido conceptual, nosleep()
es necesario. Sólo se utiliza con fines de demostración/SSCCE. Simplemente realice su tarea de larga duración allí mismo, en lugar de . Dentro de su tarea de larga duración, debe verificar si el hilo no se interrumpe de la siguiente manera:sleep()
while (!Thread.interrupted()) {
// Do your long running task here.
}
No existe una forma 100% confiable de hacer esto para ninguna tarea anterior. La tarea debe redactarse teniendo en cuenta esta capacidad.
A las bibliotecas principales de Java les gusta ExecutorService
cancelar tareas asincrónicas con interrupt()
llamadas al subproceso de trabajo. Entonces, por ejemplo, si la tarea contiene algún tipo de bucle, debes verificar su estado de interrupción en cada iteración. Si la tarea consiste en realizar operaciones de E/S, también deberían poder interrumpirse, y configurar eso puede ser complicado. En cualquier caso, tenga en cuenta que el código debe buscar activamente interrupciones; establecer una interrupción no necesariamente hace nada.
Por supuesto, si su tarea es un bucle simple, puede simplemente verificar el tiempo actual en cada iteración y darse por vencido cuando haya transcurrido un tiempo de espera específico. En ese caso, no se necesita un hilo de trabajo.
Considere usar una instancia de ExecutorService . Ambos métodos invokeAll()
y invokeAny()
están disponibles con un timeout
parámetro.
El hilo actual se bloqueará hasta que se complete el método (no estoy seguro si esto es deseable), ya sea porque las tareas se completaron normalmente o se alcanzó el tiempo de espera. Puede inspeccionar los devueltos Future
para determinar qué sucedió.
Suponiendo que el código del hilo está fuera de su control:
De la documentación de Java mencionada anteriormente:
¿Qué pasa si un hilo no responde a Thread.interrupt?
En algunos casos, puedes utilizar trucos específicos de la aplicación. Por ejemplo, si un subproceso está esperando en un socket conocido, puede cerrar el socket para que el subproceso regrese inmediatamente. Desafortunadamente, realmente no existe ninguna técnica que funcione en general. Cabe señalar que en todas las situaciones en las que un hilo en espera no responde a Thread.interrupt, tampoco responderá a Thread.stop. Estos casos incluyen ataques deliberados de denegación de servicio y operaciones de E/S en las que thread.stop y thread.interrupt no funcionan correctamente.
Línea de fondo:
Asegúrese de que todos los subprocesos puedan interrumpirse; de lo contrario, necesitará conocimientos específicos del subproceso, como tener una bandera para configurar. Tal vez pueda solicitar que se le asigne la tarea junto con el código necesario para detenerla: defina una interfaz con un stop()
método. También puede advertir cuando no pudo detener una tarea.