thread hilos java multithreading threadpool executorservice java-threads

hilos - Convertir un ExecutorService a un demonio en Java



pool de hilos java (7)

Estoy usando un ExecutoreService en Java 1.6, iniciado simplemente por

ExecutorService pool = Executors.newFixedThreadPool(THREADS).

Cuando termine mi hilo principal (junto con todas las tareas procesadas por el grupo de hilos), este grupo evitará que mi programa se cierre hasta que llame explícitamente

pool.shutdown();

¿Puedo evitar tener que llamar a esto convirtiendo de alguna manera la gestión del subproceso interno utilizado por este grupo en un subproceso de deamon? O me estoy perdiendo algo aquí.


Esta solución es similar a la de @ Marco13, pero en lugar de crear nuestro propio ThreadPoolExecutor , podemos modificar el que devuelve Executors#newFixedThreadPool(int nThreads) . Así es cómo:

ExecutorService ex = Executors.newFixedThreadPool(nThreads); if(ex instanceof ThreadPoolExecutor){ ThreadPoolExecutor tp = (ThreadPoolExecutor) ex; tp.setKeepAliveTime(time, timeUnit); tp.allowCoreThreadTimeOut(true); }


Normalmente quiero que mis hilos se ejecuten como hilos de demonio, así que agregué una clase de utilidad de la siguiente manera:

import java.util.concurrent.ThreadFactory; public class DaemonThreadFactory implements ThreadFactory { public final static ThreadFactory instance = new DaemonThreadFactory(); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setDaemon(true); return t; } }

Eso me permite pasar fácilmente DaemonThreadFactory.instance al ExecutorService , por ejemplo

ExecutorService exec = Executors.newFixedThreadPool( 4, DaemonThreadFactory.instance );

o Runnable para iniciar fácilmente un subproceso de daemon desde un Runnable , por ejemplo

DaemonThreadFactory.instance.newThread( () -> { doSomething(); } ).start();


Probablemente la solución más simple y preferida esté en la respuesta de Marco13, así que no se deje engañar por la diferencia de votos (la respuesta de la mina es algunos años más antigua) o la marca de aceptación (solo significa que la solución de la mina fue apropiada para las circunstancias del OP, no que sea la mejor).

Puedes usar ThreadFactory para establecer hilos dentro de Executor en demonios. Esto afectará el servicio del ejecutor de una manera que también se convertirá en un hilo del demonio, de modo que (y los hilos manejados por él) se detendrán si no habrá otro hilo que no sea el demonio. Aquí está el ejemplo simple:

ExecutorService exec = Executors.newFixedThreadPool(4, new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); t.setDaemon(true); return t; } }); exec.execute(YourTaskNowWillBeDaemon);

Pero si desea obtener un ejecutor que permita que su tarea termine, y al mismo tiempo llamará automáticamente a su método shutdown() cuando la aplicación esté completa, es posible que desee envolver su ejecutor con MoreExecutors.getExitingExecutorService Guava''s .

ExecutorService exec = MoreExecutors.getExitingExecutorService( (ThreadPoolExecutor) Executors.newFixedThreadPool(4), 100_000, TimeUnit.DAYS//period after which executor will be automatically closed //I assume that 100_000 days is enough to simulate infinity ); //exec.execute(YourTask); exec.execute(() -> { for (int i = 0; i < 3; i++) { System.out.println("daemon"); try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } });


Sí.

Simplemente necesita crear su propia clase ThreadFactory que crea subprocesos de daemon en lugar de subprocesos normales.


Si tiene una lista conocida de tareas, no necesita ningún hilo de daemon. Simplemente puede llamar a shutdown () en el ExecutorService después de enviar todas sus tareas.

Cuando su hilo principal esté completo, use el método awaitTermination () para dar tiempo a que se completen las tareas enviadas. Las tareas actualmente enviadas se ejecutarán, y el grupo de hilos terminará su hilo de control una vez que se hayan completado.

for (Runnable task : tasks) { threadPool.submit(task); } threadPool.shutdown(); /*... do other stuff ...*/ //All done, ready to exit while (!threadPool.isTerminated()) { //this can throw InterruptedException, you''ll need to decide how to deal with that. threadPool.awaitTermination(1,TimeUnit.SECOND); }


Ya existe una funcionalidad incorporada para crear un ExecutorService que termina todos los subprocesos después de un cierto período de inactividad: puede crear un ThreadPoolExecutor , pasarle la información de tiempo deseada y luego llamar a allowCoreThreadTimeout(true) en este servicio del ejecutor:

/** * Creates an executor service with a fixed pool size, that will time * out after a certain period of inactivity. * * @param poolSize The core- and maximum pool size * @param keepAliveTime The keep alive time * @param timeUnit The time unit * @return The executor service */ public static ExecutorService createFixedTimeoutExecutorService( int poolSize, long keepAliveTime, TimeUnit timeUnit) { ThreadPoolExecutor e = new ThreadPoolExecutor(poolSize, poolSize, keepAliveTime, timeUnit, new LinkedBlockingQueue<Runnable>()); e.allowCoreThreadTimeOut(true); return e; }

EDITAR Refiriéndose a las observaciones en los comentarios: Tenga en cuenta que este ejecutor de grupo de subprocesos no se cerrará automáticamente cuando se cierre la aplicación. El ejecutor continuará ejecutándose después de que la aplicación salga, pero no más que keepAliveTime . Si, dependiendo de los requisitos precisos de la aplicación, keepAliveTime tiene que keepAliveTime más de unos pocos segundos, la solución en la respuesta de Pshemo puede ser más apropiada: cuando los subprocesos se configuran como subprocesos del daemon, entonces terminarán inmediatamente cuando la aplicación salidas


Yo usaría la clase ThreadFactoryBuilder de Guava.

ExecutorService threadPool = Executors.newFixedThreadPool(THREADS, new ThreadFactoryBuilder().setDaemon(true).build());

Si aún no está utilizando Guava, elegiría una subclase de ThreadFactory como la descrita en la parte superior de la respuesta de Pshemo.