2009-11-05 16 views
25

tengo esta pregunta bastante simple sobre el ThreadPoolExecutor. Tengo la siguiente situación: debo consumir objetos de una cola, crear las tareas apropiadas para ellos y enviarlos al ThreadPoolExecutor. Esto es bastante simple. Pero dentro de un escenario de cierre muchos trabajadores pueden ser puestos en cola para la ejecución. Dado que una de esas tareas puede estar ejecutándose durante una hora, y quiero un apagado relativamente rápido y elegante de la aplicación, quiero descartar todas las tareas en cola del ThreadPoolExecutor mientras que las tareas que ya están en proceso deben completarse normalmente.Eliminando todas las tareas en cola de un ThreadPoolExecutor

La documentación del ThreadPoolExecutor tiene un método remove() pero solo permite eliminar tareas específicas. purge() solo funciona para tareas Future ya canceladas. Mi idea era borrar la cola que contenía todas las tareas en cola. El ThreadPoolExecutor proporciona acceso a esta cola interna, pero la documentación indica:

Método getQueue() permite el acceso a la cola de obra para fines de monitoreo y depuración. El uso de este método para cualquier otro propósito es fuertemente desaconsejado.

Así que agarrar esta cola y borrarla no es una opción. Además, este fragmento de la documentación dice:

métodos

dos pilas, remove (java.lang.Runnable) y de purga() están disponibles para ayudar en la recuperación de almacenamiento cuando un gran número de tareas se vuelven cola cancelado .

¿Cómo? Claro, puedo mantener una lista de todas las tareas que envié al ejecutor y, en caso de cierre, repito todas las entradas y las elimino del ThreadPoolExecutor con el método remove() ... pero ... vamos, este es un pérdida de memoria y una molestia para mantener esta lista. (Eliminando tareas ya ejecutadas, por ejemplo)

¡Agradezco cualquier sugerencia o solución!

Respuesta

9

¿Ha considerado envolver el ExecutorService? Cree un

CleanShutdownExecutorService implements Executor 

que delega todas las llamadas a otro ejecutor, pero mantiene los futuros en una lista propia. CleanShutdownExecutorService puede tener un método cancelRemainingTasks() que invoca shutdown(), luego llama a cancel (false) en todos los futuros de su lista.

+0

Este podría ser el enfoque más limpio, por lo tanto, acepto esta respuesta. :-) Incluso esperaba que ya haya algo así ... así que: codifiquemos esto. :-) – Malax

4

Como ExecutorService.shutdown() no está haciendo lo suficiente y ExecutorService.shutdownNow() está haciendo demasiado supongo que tienes que escribir algo en el medio: recuerde todas las tareas presentadas y eliminarlos manualmente después (o antes) llamando shutdown().

+0

"Inicia un cierre ordenado en el que se ejecutan las tareas enviadas anteriormente, pero no se aceptarán nuevas tareas". Tengo varias tareas enviadas que ya no deberían ejecutarse. Pero las tareas ** ejecutadas ** no deberían finalizar. – Malax

+0

Has editado tu respuesta para que mi comentario ya no sea completamente válido. Sin embargo, la documentación de shutdownNow() indica: "Intenta detener todas las tareas que se ejecutan activamente". Que no es lo que quiero :) – Malax

+0

Oh, cierto, sobrevendí esa mitad de la oración. Bueno, supongo que tu única opción es recordar todos los 'ejecutables' enviados y eliminarlos manualmente. Voy a editar en consecuencia. – Bombe

1

La respuesta de Bombe es exactamente lo que quieres. shutdownNow() detiene todo utilizando el enfoque nuke y pave. Esto es lo mejor que puede hacer, salvo crear una subclasificación de la implementación de ThreadPoolExecutor que está utilizando.

0

Una solución loca y sucio que podría trabajar (pensamiento no real a través de o probado) sería para sobrescribir el interrupt() de sus WorkerTasks que sólo en caso de que se establece un valor global de negarse a apagarse cuando interrupt() se llama en ellos por shutdownNow ()

Eso debería permitirle usar shutdownNow() no?

0

Indique al grupo de subprocesos que se cierre, getQueue, para cada resultado en Runnables individuales, elimine cada Runnable utilizando el método remove. Según el tipo de cola, es posible que pueda detener las eliminaciones de forma anticipada en función de los valores devueltos.

Básicamente, esto está agarrando la cola y despejándola, solo borrando a través de los métodos que funcionan. En lugar de recordar manualmente todas las presentaciones, utiliza el hecho de que el grupo de subprocesos ya tiene que recordar todas las presentaciones. Sin embargo, es probable que necesites hacer una copia defensiva de la cola, ya que creo que es una vista en vivo, y por lo tanto eliminarla probablemente causaría una excepción de modificación simultánea si estuvieras iterando/for-itando sobre la vista en vivo.

12

Solía ​​trabajar en una aplicación con subprocesos de larga ejecución. Hacemos esto en el cierre,

BlockingQueue<Runnable> queue = threadPool.getQueue(); 
List<Runnable> list = new ArrayList<Runnable>(); 
int tasks = queue.drainTo(list); 

La lista se guarda en un archivo. Al inicio, la lista se agrega al grupo para que no perdamos ningún trabajo.

+2

Agradable además de mi pregunta. :-) En mi caso, la persistencia de las tareas no es un problema. Pero su adición puede ayudar a otros, ¡gracias! :) – Malax

+0

No estoy seguro de que sea el enfoque correcto. Si se cierra mediante shutdown(), espera hasta que todo finalice (incluso tareas en cola), si lo hace con shutdownNow(), ese método ya le devuelve la lista agotada de tareas en cola. Solo digo para el caso. – Whimusical

0

¿No funciona awaitTermination(long timeout, TimeUnit unit) after shutdown?

executor.shutdown(); executor.awaitTermination (60, TimeUnit.SECONDS)

1

Puede intentar allowCoreThreadTimeOut(true);

+0

Debería desarrollar su respuesta y dejar en claro que en realidad está respondiendo al OP. –

3

Ésta es una cuestión de edad, pero en caso de que esto ayude a alguien más: puede establecer un valor lógico volátil cuando se llama a shutdown(), y que cada tarea enviada finalice si ese booleano está configurado antes de realmente comenzar. Esto permitirá tareas que realmente han comenzado a completarse, pero evitará que las tareas en cola comiencen su actividad real.

Cuestiones relacionadas