Parece imposible hacer un grupo de subprocesos en caché con un límite en el número de subprocesos que puede crear.
Así es como se implementa Executors.newCachedThreadPool estático en la biblioteca estándar de Java:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
Entonces, usando esa plantilla para crear un grupo de subprocesos en caché de tamaño fijo:
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new SynchronusQueue<Runable>());
Ahora, si usa esto y envía 3 tareas, todo estará bien. El envío de cualquier otra tarea dará como resultado excepciones de ejecución rechazadas.
Intentando esto:
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runable>());
El resultado será que todos los hilos se ejecuten secuencialmente. Es decir, el grupo de subprocesos nunca hará más de un subproceso para manejar sus tareas.
Este es un error en el método de ejecución de ThreadPoolExecutor? O tal vez esto es intencional? ¿O hay alguna otra manera?
Editar: quiero algo exactamente como el grupo de subprocesos en caché (crea subprocesos bajo demanda y luego los mata después de un tiempo de espera) pero con un límite en el número de subprocesos que puede crear y la capacidad de continuar haciendo cola tareas adicionales una vez que ha golpear su límite de hilo. Según la respuesta de sjlee, esto es imposible. Mirando el método execute () de ThreadPoolExecutor, es realmente imposible. Necesitaría subclasificar ThreadPoolExecutor y anular execute () de manera similar a SwingWorker, pero lo que SwingWorker hace en execute () es un hack completo.
fuente
Respuestas:
ThreadPoolExecutor tiene los siguientes comportamientos clave, y estos problemas pueden explicarse por estos comportamientos.
Cuando se envían tareas,
En el primer ejemplo, tenga en cuenta que SynchronousQueue tiene esencialmente un tamaño de 0. Por lo tanto, en el momento en que alcanza el tamaño máximo (3), la política de rechazo entra en acción (# 4).
En el segundo ejemplo, la cola de elección es un LinkedBlockingQueue que tiene un tamaño ilimitado. Por lo tanto, te quedas atascado con el comportamiento # 2.
Realmente no puede jugar mucho con el tipo en caché o el tipo fijo, ya que su comportamiento está casi completamente determinado.
Si desea tener un grupo de subprocesos dinámico y acotado, debe usar un tamaño de núcleo positivo y un tamaño máximo combinados con una cola de un tamaño finito. Por ejemplo,
Anexo : esta es una respuesta bastante antigua, y parece que JDK cambió su comportamiento cuando se trata del tamaño del núcleo de 0. Desde JDK 1.6, si el tamaño del núcleo es 0 y el grupo no tiene ningún subproceso, el ThreadPoolExecutor agregará un hilo para ejecutar esa tarea. Por lo tanto, el tamaño del núcleo de 0 es una excepción a la regla anterior. Gracias Steve por llamarme la atención.
fuente
allowCoreThreadTimeOut
para que esta respuesta sea perfecta. Ver la respuesta de @ user1046052A menos que me haya perdido algo, la solución a la pregunta original es simple. El siguiente código implementa el comportamiento deseado como se describe en el póster original. Generará hasta 5 hilos para trabajar en una cola ilimitada y los hilos inactivos terminarán después de 60 segundos.
fuente
Tuve el mismo problema. Como ninguna otra respuesta reúne todos los problemas, agrego la mía:
Ahora está claramente escrito en documentos : si usa una cola que no bloquea (
LinkedBlockingQueue
) la configuración de subprocesos máximos no tiene efecto, solo se usan subprocesos principales.entonces:
Este ejecutor tiene:
No hay concepto de subprocesos máximos ya que estamos usando una cola ilimitada. Esto es bueno porque dicha cola puede hacer que el ejecutor cree una cantidad masiva de subprocesos extra no centrales si sigue su política habitual.
Una cola de tamaño máximo
Integer.MAX_VALUE
.Submit()
lanzaráRejectedExecutionException
si el número de tareas pendientes excedeInteger.MAX_VALUE
. No estoy seguro de que primero se nos acabe la memoria o esto sucederá.Tiene 4 hilos principales posibles. Los subprocesos de núcleo inactivo salen automáticamente si están inactivos durante 5 segundos. Entonces, sí, los subprocesos estrictamente a pedido. El número se puede variar utilizando el
setThreads()
método.Se asegura de que el número mínimo de subprocesos principales nunca sea inferior a uno, o
submit()
rechazará todas las tareas. Dado que los subprocesos centrales deben ser> = subprocesos máximos, el método tambiénsetThreads()
establece subprocesos máximos, aunque la configuración de subprocesos máximos es inútil para una cola ilimitada.fuente
En su primer ejemplo, las tareas posteriores se rechazan porque
AbortPolicy
es el valor predeterminadoRejectedExecutionHandler
. ThreadPoolExecutor contiene las siguientes políticas, que puede cambiar mediante elsetRejectedExecutionHandler
método:Parece que quiere un grupo de subprocesos en caché con CallerRunsPolicy.
fuente
Ninguna de las respuestas aquí solucionó mi problema, que tenía que ver con la creación de una cantidad limitada de conexiones HTTP utilizando el cliente HTTP de Apache (versión 3.x). Como me llevó algunas horas encontrar una buena configuración, compartiré:
Esto crea un
ThreadPoolExecutor
que comienza con cinco y contiene un máximo de diez hilos que se ejecutan simultáneamenteCallerRunsPolicy
para ejecutar.fuente
Según el Javadoc para ThreadPoolExecutor:
(El énfasis es mío).
La respuesta de Jitter es lo que quieres, aunque la mía responde a tu otra pregunta. :)
fuente
Hay una opción más. En lugar de usar el nuevo SynchronousQueue, también puede usar cualquier otra cola, pero debe asegurarse de que su tamaño sea 1, de modo que obligue al servicio del ejecutor a crear un nuevo hilo.
fuente
No parece que ninguna de las respuestas realmente responda la pregunta, de hecho, no puedo ver una forma de hacerlo, incluso si subclasifica de PooledExecutorService ya que muchos de los métodos / propiedades son privados, por ejemplo, haciendo que addIfUnderMaximumPoolSize esté protegido, podría Haz lo siguiente:
Lo más cerca que estuve fue esto, pero incluso eso no es una muy buena solución
ps no probado lo anterior
fuente
Aquí hay otra solución. Creo que esta solución se comporta como lo desea (aunque no está orgullosa de esta solución):
fuente
Esto es lo que quieres (al menos supongo que sí). Para una explicación, verifique la respuesta de Jonathan Feinberg
Executors.newFixedThreadPool(int n)
fuente
Puede usar
ThreadPoolExecutor
como lo sugiere @sjleePuede controlar el tamaño del grupo de forma dinámica. Echa un vistazo a esta pregunta para más detalles:
Grupo de subprocesos dinámicos
O
Puede usar newWorkStealingPool API, que se ha introducido con java 8.
De forma predeterminada, el nivel de paralelismo se establece en el número de núcleos de CPU en su servidor. Si tiene un servidor de CPU de 4 núcleos, el tamaño del grupo de subprocesos sería 4. Esta API devuelve el
ForkJoinPool
tipo deExecutorService
y permite robar trabajo de subprocesos inactivos robando tareas de subprocesos ocupados en ForkJoinPool.fuente
El problema se resumió de la siguiente manera:
Antes de señalar la solución, explicaré por qué las siguientes soluciones no funcionan:
Esto no pondrá en cola ninguna tarea cuando se alcance el límite de 3 porque SynchronousQueue, por definición, no puede contener ningún elemento.
Esto no creará más de un subproceso porque ThreadPoolExecutor solo crea subprocesos que exceden el corePoolSize si la cola está llena. Pero LinkedBlockingQueue nunca está lleno.
Esto no reutilizará subprocesos hasta que se haya alcanzado corePoolSize porque ThreadPoolExecutor aumenta el número de subprocesos hasta que se alcance corePoolSize incluso si los subprocesos existentes están inactivos. Si puede vivir con esta desventaja, entonces esta es la solución más fácil para el problema. También es la solución descrita en "Concurrencia de Java en la práctica" (nota al pie de página en p172).
La única solución completa al problema descrito parece ser la que implica anular el
offer
método de la cola y escribir un mensajeRejectedExecutionHandler
como se explica en las respuestas a esta pregunta: ¿Cómo hacer que ThreadPoolExecutor aumente los hilos al máximo antes de hacer cola?fuente
Esto funciona para Java8 + (y otros, por ahora ..)
donde 3 es el límite de hilos y 5 es tiempo de espera para hilos inactivos.
Si desea verificar si funciona usted mismo , aquí está el código para hacer el trabajo:
salida del código anterior para mí es
fuente