Respuesta

141

creo que los documentos explican la diferencia y el uso de estas dos funciones bastante bien:

newFixedThreadPool

Crea un grupo de subprocesos que reutiliza un número fijo de hilos que operan fuera una cola sin límites compartida . En cualquier punto , como mucho nThreads hilos serán tareas activas de procesamiento. Si se envían tareas adicionales cuando todos los hilos están activos, esperarán en la cola hasta que haya un hilo disponible. Si alguna secuencia finaliza debido a un fallo durante la ejecución antes del cierre, una nueva tomará el lugar si es necesario para ejecutar tareas posteriores. Los subprocesos en el grupo existirán hasta que se cierre explícitamente .

newCachedThreadPool

Crea un grupo de subprocesos que crea nuevos hilos como sea necesario, pero reutilizará hilos ya construidos cuando que están disponibles. Estas agrupaciones generalmente mejorarán el rendimiento de los programas que ejecutan muchas tareas asíncronas de corta duración . Las llamadas para ejecutar reutilizarán subprocesos previamente construidos si están disponibles. Si no hay ningún subproceso existente disponible, se creará un nuevo subproceso y se agregará al grupo. Se terminaron los hilos que no se han usado para sesenta segundos y se eliminó del caché. Por lo tanto, un grupo que permanezca inactivo durante el tiempo suficiente no consumirá ningún recurso. Tenga en cuenta que agrupaciones con propiedades similares pero se pueden crear detalles diferentes (por ejemplo, parámetros de tiempo de espera) utilizando constructores de ThreadPoolExecutor.

En términos de recursos, el newFixedThreadPool mantendrá todos los subprocesos en ejecución hasta que se terminen explícitamente. En el newCachedThreadPool, los hilos que no se han utilizado durante sesenta segundos se terminan y se eliminan del caché.

Dado esto, el consumo de recursos dependerá en gran medida de la situación. Por ejemplo, si tiene una gran cantidad de tareas de ejecución prolongada, sugeriría FixedThreadPool. En cuanto al CachedThreadPool, los documentos dicen que "estos grupos generalmente mejorarán el rendimiento de los programas que ejecutan muchas tareas asincrónicas de corta duración".

+1

sí he pasado por el problema docs..the se ... fixedThreadPool está causando un error de falta de memoria @ 3 hilos .. donde como cachedPool está creando internamente solo un hilo ... al aumentar el tamaño del montón , estoy obteniendo el mismo rendimiento para ambos ... ¡hay algo más que me falta! – hakish

+1

¿Estás proporcionando algún Threadfactory al ThreadPool? Supongo que podría estar almacenando algún estado en los subprocesos que no está siendo recolectado. Si no, tal vez su programa se está ejecutando tan cerca del tamaño de límite de montón que con la creación de 3 subprocesos provoca una OutOfMemory.Además, si cachedPool está creando internamente solo un hilo, esto indica que tus tareas se están ejecutando sincronizadas. –

3

Debe usar newCachedThreadPool solo cuando tiene tareas asincrónicas de corta duración como se indica en Javadoc, si envía tareas que tardan más en procesarse, terminará creando demasiados hilos.Puede aplicar 100% de CPU si envía tareas de ejecución larga a mayor velocidad a newCachedThreadPool (http://rashcoder.com/be-careful-while-using-executors-newcachedthreadpool/).

7

Correcto, Executors.newCachedThreadPool() no es una gran opción para el código del servidor que sirve a clientes múltiples y solicitudes simultáneas.

¿Por qué? Hay básicamente dos (relacionados) problemas con él:

  1. Es sin límites, lo que significa que usted está abriendo la puerta para que cualquiera pueda paralizar su JVM por la simple inyección de más trabajo en el servicio (ataque DoS). Los subprocesos consumen una cantidad no despreciable de memoria y también aumentan el consumo de memoria en función de su trabajo en curso, por lo que es bastante fácil volcar un servidor de esta manera (a menos que tenga otros interruptores en su lugar).

  2. El problema ilimitado se ve agravado por el hecho de que el Ejecutor está liderado por un SynchronousQueue, lo que significa que hay una transferencia directa entre el encargado de tareas y el grupo de subprocesos. Cada nueva tarea creará un nuevo hilo si todos los hilos existentes están ocupados. En general, esta es una mala estrategia para el código del servidor. Cuando la CPU se satura, las tareas existentes tardan más en finalizar. Sin embargo, se envían más tareas y se crean más hilos, por lo que las tareas tardan más y más en completarse. Cuando la CPU está saturada, más hilos definitivamente no es lo que necesita el servidor.

Estas son mis recomendaciones:

Utilice un grupo de subprocesos de tamaño fijo o una Executors.newFixedThreadPoolThreadPoolExecutor. con un número máximo conjunto de hilos;

9

Si ve el código en grepcode, verá que llaman al ThreadPoolExecutor. internamente y establecen sus propiedades. Puede crear uno para tener un mejor control de sus requisitos.

public static ExecutorService newFixedThreadPool(int nThreads) { 
    return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, 
new LinkedBlockingQueue<Runnable>()); 
} 

public static ExecutorService newCachedThreadPool() { 
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 
             60L, TimeUnit.SECONDS, 
             new SynchronousQueue<Runnable>()); 
} 
+1

Exactamente, un ejecutor de subprocesos en caché con un límite superior sano y, por ejemplo, 5-10 minutos de cosecha inactiva es perfecto para la mayoría de las ocasiones. –

5

Si no está preocupado por la cola sin límites de Callable/Ejecutables tareas, puede utilizar uno de ellos. Como lo sugirió bruno, yo también prefiero newFixedThreadPool a newCachedThreadPool entre estos dos.

Pero ThreadPoolExecutor proporciona características más flexibles en comparación con los dos o newFixedThreadPoolnewCachedThreadPool

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, 
RejectedExecutionHandler handler) 

Ventajas:

  1. Usted tiene el control total sobre BlockingQueue tamaño. No es ilimitado a diferencia de las dos opciones anteriores. No saldré del error de memoria debido al gran apilamiento de tareas Pendientes/Invocables pendientes en una turbulencia inesperada en el sistema.

  2. que se pueden implementar a medida manejo de la política de rechazo o utilizar una de las políticas:

    1. En el defecto ThreadPoolExecutor.AbortPolicy, el guía lanza el RejectedExecutionException tiempo de ejecución al rechazo.

    2. En ThreadPoolExecutor.CallerRunsPolicy, el subproceso que invoca ejecutar se ejecuta la tarea. Esto proporciona un mecanismo de control de retroalimentación simple que ralentizará la velocidad con la que se envían las tareas nuevas.

    3. En ThreadPoolExecutor.DiscardPolicy, una tarea que no se puede ejecutar simplemente se descarta.

    4. En ThreadPoolExecutor.DiscardOldestPolicy, si el ejecutor no se apaga, la tarea a la cabeza de la cola de trabajo se deja caer, y luego se vuelve a intentar la ejecución (que puede fracasar de nuevo, haciendo que esta se repita.)

  3. puede implementar la fábrica de hilos preferidos para los casos de uso a continuación:

    1. para establecer un nombre más descriptivo hilo
    2. para establecer hilo estado daemon
    3. para establecer la prioridad de hilo
39

Sólo para completar las otras respuestas, me gustaría citar Effective Java, 2ª edición, por Joshua Bloch, capítulo 10, artículo 68:

" Elegir el servicio de ejecutor para una aplicación en particular puede ser complicado. Si estás escribiendo un pequeño programa , o un servidor con poca carga , utilizando Executors.new- CachedThreadPool es generalmente una buena opción , ya que requiere ninguna configuración y, en general “hace lo correcto.” Pero un grupo de subprocesos en caché es no es una buena opción para un servidor de producción muy cargado !

En un grupo de subprocesos en caché , tareas presentados no se ponen en cola pero pasa a las manos de un hilo de ejecución. Si no hay subprocesos disponibles, se crea uno nuevo. Si un servidor está tan cargado que todas sus CPU se utilizan por completo y llegan más tareas, se crearán más subprocesos, lo que empeorará las cosas.

Por lo tanto, en un servidor de producción muy cargado, es mucho mejor usar Executors.newFixedThreadPool, que le da una piscina con un número fijo de hilos, o directamente a través de la clase ThreadPoolExecutor, para un control máximo . "