Quiero ejecutar un hilo por un tiempo fijo. Si no se completa dentro de ese tiempo, quiero matarlo, lanzar alguna excepción o manejarlo de alguna manera. ¿Cómo puede hacerse esto?
Una forma de hacerlo como descubrí de este hilo es usar un TimerTask dentro del método run () del hilo.
¿Hay alguna solución mejor para esto?
EDITAR: Agregar una recompensa ya que necesitaba una respuesta más clara. El código de ExecutorService que se proporciona a continuación no soluciona mi problema. ¿Por qué debería dormir () después de ejecutar (algún código, no tengo control sobre este fragmento de código)? Si se completa el código y se interrumpe el sueño (), ¿cómo puede ser un tiempo de espera?
La tarea que debe ejecutarse no está bajo mi control. Puede ser cualquier pieza de código. El problema es que este fragmento de código podría encontrarse 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 el subproceso y necesita saber el estado de la tarea (es decir, si se agotó el tiempo de espera o si se produjo alguna excepción o si es un éxito). Si la tarea entra en un bucle infinito, mi hilo padre sigue esperando indefinidamente, lo cual no es una situación ideal.
fuente
sleep()
fue solo un trozo para representar la "tarea de ejecución prolongada". Simplemente reemplácelo con su tarea real;)interrupt()
llamadas en su hilo ... no todas las llamadas de "bloqueo" lo hacen, como intenté señalar en mi respuesta. Los detalles de la tarea que está intentando abortar marcan una gran diferencia en el enfoque que debe usarse. Sería útil más información sobre la tarea.Respuestas:
De hecho en lugar usar
ExecutorService
en lugar deTimer
, aquí hay un SSCCE :Juegue un poco con el
timeout
argumento en elFuture#get()
método, por ejemplo, aumente a 5 y verá que el hilo termina. Puede interceptar el tiempo de espera en elcatch (TimeoutException e)
bloque.Actualización: para aclarar un malentendido conceptual, el
sleep()
es no necesaria. Solo se utiliza con fines de demostración / SSCCE. Simplemente haga su tarea de larga duración allí mismo en lugar desleep()
. Dentro de su tarea de larga ejecución, debe verificar si el hilo no se interrumpe de la siguiente manera:fuente
Thread.sleep(4000)
con alguna otra declaración de larga duración y el ejemplo no funcionará. En otras palabras, este ejemplo funcionaría solo siTask
está diseñado para comprender elThread.isInterrupted()
cambio de estado.No hay una forma 100% confiable de hacer esto para cualquier tarea antigua. La tarea tiene que ser escrita con esta habilidad en mente.
Las bibliotecas principales de Java, como
ExecutorService
cancelar tareas asincrónicas coninterrupt()
llamadas en el subproceso de trabajo. Entonces, por ejemplo, si la tarea contiene algún tipo de ciclo, debería verificar su estado de interrupción en cada iteración. Si la tarea está haciendo operaciones de E / S, también deberían ser interrumpibles, y configurarlo puede ser complicado. En cualquier caso, tenga en cuenta que el código debe verificar activamente las interrupciones; establecer una interrupción no necesariamente hace nada.Por supuesto, si su tarea es un ciclo simple, puede verificar el tiempo actual en cada iteración y darse por vencido cuando haya transcurrido un tiempo de espera especificado. Un hilo de trabajo no es necesario en ese caso.
fuente
execute()
método de la interfaz principalExecutor
puede ejecutar una tarea en el subproceso de llamada. No hay una declaración similar para lossubmit()
métodos deExecutorService
esasFuture
instancias de retorno . La implicación del servicio es que hay subprocesos de trabajo que deben limpiarse mediante apagado, y que las tareas se ejecutan de forma asincrónica. Dicho esto, no hay nada en el contrato que diga queExecutorService
está prohibido ejecutar tareas en el hilo de envío; esas garantías provienen de las API de implementación, como lasExecutors
fábricas.Considere usar una instancia de ExecutorService . Ambos
invokeAll()
y losinvokeAny()
métodos están disponibles con untimeout
parámetro.El subproceso 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 las devoluciones
Future
para determinar qué sucedió.fuente
Asumiendo que el código del hilo está fuera de su control:
De la documentación de Java mencionada anteriormente:
Línea de fondo:
Asegúrese de que todos los hilos se puedan interrumpir, o de lo contrario necesita un conocimiento específico del hilo, como tener una bandera para establecer. Tal vez pueda requerir que se le dé 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.fuente
BalusC dijo:
Pero si reemplaza
Thread.sleep(4000);
con,for (int i = 0; i < 5E8; i++) {}
entonces no se compila, porque el bucle vacío no arroja unInterruptedException
.Y para que el hilo sea interrumpible, necesita lanzar un
InterruptedException
.Esto me parece un problema grave. No puedo ver cómo adaptar esta respuesta para trabajar con una tarea general de larga duración.
Editado para agregar: lo volví a plantear como una nueva pregunta: [ interrumpiendo un hilo después de un tiempo fijo, ¿tiene que arrojar InterruptedException? ]
fuente
Creo que debería echar un vistazo a los mecanismos adecuados de manejo de concurrencia (los hilos que se ejecutan en bucles infinitos no suena bien per se, por cierto). Asegúrese de leer un poco sobre el tema "matar" o "detener" temas .
Lo que está describiendo, suena muy parecido a una "cita", por lo que es posible que desee echar un vistazo a la CyclicBarrier .
Puede haber otras construcciones (como usar CountDownLatch, por ejemplo) que pueden resolver su problema (un hilo esperando con un tiempo de espera para el pestillo, el otro debería contar el pestillo si ha hecho su trabajo, lo que liberaría su primer hilo después un tiempo de espera o cuando se invoca la cuenta regresiva del pestillo).
Por lo general, recomiendo dos libros en esta área: programación concurrente en Java y concurrencia de Java en la práctica .
fuente
Creé una clase auxiliar solo para esto hace algún tiempo. Funciona genial:
Se llama así:
fuente
Le publico un código que muestra una forma de resolver el problema. Como ejemplo, estoy leyendo un archivo. Puede usar este método para otra operación, pero necesita implementar el método kill () para que se interrumpa la operación principal.
Espero eso ayude
Saludos
fuente
Aquí está mi clase de ayuda realmente simple de usar para ejecutar o llamar un código de Java :-)
Esto se basa en la excelente respuesta de BalusC
fuente
El siguiente fragmento iniciará una operación en un hilo separado, luego esperará hasta 10 segundos para que se complete la operación. Si la operación no se completa a tiempo, el código intentará cancelar la operación y luego continuará felizmente. Incluso si la operación no se puede cancelar fácilmente, el subproceso principal no esperará a que finalice el subproceso secundario.
El
getExecutorService()
método puede implementarse de varias maneras. Si no tiene ningún requisito en particular, simplemente puede solicitar laExecutors.newCachedThreadPool()
agrupación de subprocesos sin límite superior en el número de subprocesos.fuente
SomeClass
yFuture
?Una cosa que no he visto mencionado es que matar hilos es generalmente una mala idea. Existen técnicas para hacer que los métodos roscados sean abortables de forma limpia , pero eso es diferente a simplemente matar un hilo después de un tiempo de espera.
El riesgo con lo que está sugiriendo es que probablemente no sepa en qué estado estará el hilo cuando lo mate, por lo que se arriesga a introducir inestabilidad. Una mejor solución es asegurarse de que su código enhebrado no se cuelgue o responda bien a una solicitud de cancelación.
fuente
Gran respuesta de BalusC:
pero solo para agregar que el tiempo de espera en sí mismo no interrumpe el hilo en sí. incluso si está comprobando con while (! Thread.interrupted ()) en su tarea. si desea asegurarse de que el subproceso esté detenido, también debe asegurarse de que se invoque future.cancel () cuando se capture la excepción de tiempo de espera.
fuente
Creo que la respuesta depende principalmente de la tarea en sí.
Si la primera respuesta es sí y la segunda es no, podría mantenerlo tan simple como esto:
Si esto no es una opción, limite sus requisitos o muestre algún código.
fuente
Estaba buscando un ExecutorService que pueda interrumpir todos los Runnables ejecutados por él, pero no encontré ninguno. Después de unas horas, creé uno de la siguiente manera. Esta clase se puede modificar para mejorar la robustez.
Uso:
fuente
Ahora, me encuentro con un problema como este. Pasa a decodificar la imagen. El proceso de decodificación lleva demasiado tiempo para que la pantalla se mantenga negra. Agrego un controlador de tiempo: cuando el tiempo es demasiado largo, aparece el hilo actual. El siguiente es el diff:
fuente
Yo tuve el mismo problema. Entonces se me ocurrió una solución simple como esta.
Garantiza que si el bloque no se ejecutó dentro del límite de tiempo. el proceso terminará y arrojará una excepción.
ejemplo:
fuente
En la solución dada por BalusC , el hilo principal permanecerá bloqueado durante el tiempo de espera. Si tiene un grupo de subprocesos con más de un subproceso, necesitará el mismo número de subprocesos adicionales que utilizará la llamada de bloqueo Future.get (tiempo de espera largo, unidad TimeUnit) para esperar y cerrar el subproceso si excede el período de tiempo de espera.
Una solución genérica a este problema es crear un decorador ThreadPoolExecutor que pueda agregar la funcionalidad de tiempo de espera. Esta clase de decorador debe crear tantos subprocesos como ThreadPoolExecutor, y todos estos subprocesos deben usarse solo para esperar y cerrar ThreadPoolExecutor.
La clase genérica debe implementarse como a continuación:
El decorador anterior se puede usar de la siguiente manera:
fuente