ejemplo java multithreading concurrency executorservice

java - ejemplo - El programa no termina inmediatamente cuando se realizan todas las tareas de ExecutorService



executors java (5)

Pongo un montón de objetos ejecutables en un ExecutorService:

// simplified content of main method ExecutorService threadPool = Executors.newCachedThreadPool(); for(int i = 0; i < workerCount; i++) { threadPool.execute(new Worker()); }

Espero que mi programa / proceso se detenga inmediatamente después de que todos los trabajadores hayan terminado. Pero de acuerdo con mi registro, toma otros 20-30 segundos hasta que eso suceda. Los trabajadores no asignan ningún recurso, de hecho, no hacen nada en este momento.

No me malinterpretes, este no es un problema crucial para mí, solo trato de entender lo que está sucediendo y me pregunto si este es un comportamiento normal.


Espero que mi programa / proceso se detenga inmediatamente después de que todos los trabajadores hayan terminado. Pero de acuerdo con mi registro, toma otros 20-30 segundos hasta que eso suceda. Los trabajadores no asignan ningún recurso, de hecho, no hacen nada en este momento.

El problema es que no está cerrando su ExecutorService . Después de enviar todos los trabajos al servicio, debe cerrar el servicio o la JVM no terminará a menos que todos los subprocesos en él sean subprocesos de daemon. Si no apaga el grupo de subprocesos, los subprocesos asociados con el Servicio de ExecutorService , de nuevo si no es un demonio, detendrán la JVM. Si ha enviado alguna tarea a un grupo de subprocesos almacenados en caché, tendrá que esperar a que los subprocesos se agote y finalice antes de que finalice la JVM.

ExecutorService threadPool = Executors.newCachedThreadPool(); for(int i = 0; i < workerCount; i++) { threadPool.execute(new Worker()); } // you _must_ do this after submitting all of your workers threadPool.shutdown();

Lo más probable es que iniciar los subprocesos como daemon no sea lo que quiere hacer porque su aplicación puede detenerse antes de que las tareas se hayan completado y todas las tareas se terminarán de inmediato en ese momento. De las 178 veces que utilizamos las clases ExecutorService en nuestro código de producción, solo 2 de ellas se iniciaron como subprocesos de daemon. El resto está correctamente cerrado.

Si necesita forzar a un ExecutorService para que se detenga cuando la aplicación está saliendo, entonces use shutdownNow() con el manejo adecuado de los indicadores de interrupción del hilo está en orden.


Básicamente, en un ExecutorService usted llama a shutdown () y luego awaitTermination ():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4); while(...) { taskExecutor.execute(new MyTask()); } taskExecutor.shutdown(); try { taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { ... }


Desde el javadoc para Executors.newCachedThreadPool() :

Los hilos que no se han utilizado durante sesenta segundos se terminan y se eliminan de la memoria caché.

Por lo general, es una buena idea llamar a shutdown() en un ExecutorService si sabe que no se le enviarán tareas nuevas. Luego, todas las tareas en la cola se completarán, pero el servicio se cerrará de inmediato.

(Alternativamente, si no le importa si todas las tareas están completas, por ejemplo, si están manejando cálculos de fondo que son irrelevantes una vez que se ha ido su interfaz de usuario principal), puede crear un ThreadFactory que establezca todos los hilos de ese grupo. demonio.)


Para subprocesos múltiples de la solución ExecutorService es threadPool.shutdown ();


Executors.newCachedThreadPool() usa Executors.defaultThreadFactory() para su ThreadFactory . Los javadocs de defaultThreadFactory dicen que "cada subproceso nuevo se crea como un subproceso no daemon " (énfasis añadido). Por lo tanto, los subprocesos creados para newCachedThreadPool no son daemon. Eso significa que evitarán que la JVM salga de forma natural (por "naturalmente" quiero decir que todavía puede llamar a System.exit(1) o matar el programa para detener la JVM).

La razón por la que la aplicación termina es que cada subproceso creado dentro de newCachedThreadPool agota y se cierra después de un tiempo de inactividad. Cuando el último de ellos se cierre solo, si a tu aplicación no le quedan hilos que no sean de demonio, se cerrará.

Puede (y debe) cerrar ExecutorService manualmente a través de shutdown o shutdownNow .

Vea también el JavaDoc for Thread , que habla acerca de la daemon-ness.