¿Hilos o ThreadPool? ThreadPool fijo o dinámico?

8

Tengo un programa java que escucha en un puerto para la entrada. Basado en Input, llama a un servicio web y luego devuelve un éxito / falla al programa cliente.

Bifurco un hilo para cada conexión de cliente. La respuesta al cliente que se conecta al programa debe ser rápida.

Estas son las opciones que estoy considerando

  1. usar hilos regulares
  2. utilizar ExecutorServiceconnewFixedThreadPool
  3. utilizar ExecutorServiceconnewCachedThreadPool

La razón por la que estoy considerando grupos es porque mis hilos son de corta duración: simplemente llaman a un servicio web, devuelven el resultado al cliente y cierran la conexión.

No creo newFixedThreadPoolque sea lo correcto porque las conexiones estarían esperando en las colas para obtener un hilo.

newCachedThreadPoolhubiera sido perfecto, excepto por una cosa: los hilos mueren después de un minuto. En mi caso, recibo ráfagas de conexiones, es decir, conexiones múltiples y luego puede haber una pausa durante unos minutos y luego nuevamente ráfagas. Creo que los hilos en CachedThreadPool morirían y tendrían que volver a crearse, por lo que en este caso, a veces puede funcionar como # 1.

Idealmente, me hubiera encantado tener newCachedThreadPoolun mínimo, es decir, una configuración que dice que el número de subprocesos nunca iría por debajo de 20, por lo que los subprocesos inactivos se eliminan pero nunca se permite que pasen por debajo de un umbral mínimo.

¿Hay algo como esto disponible? ¿O hay mejores alternativas?

usuario93353
fuente
Eche un vistazo a QuickServer.org en lugar del propio servidor de socket. Hace lo que quiere -> socket y subprocesos y tiene muchas muestras. puede hacerlo funcionar en 30 minutos. Probado y estable, lo he usado en 3 proyectos. "Marco / biblioteca Java de código abierto para la creación rápida de aplicaciones robustas de servidor TCP
multicliente

Respuestas:

8

Los métodos en la clase Executors son solo métodos convenientes para casos de uso comunes. Hay muchas más opciones disponibles para crear grupos de subprocesos.

Para crear lo mismo que Executors.newCachedThreadPool () pero con un mínimo de 20 subprocesos (esto se copia del método en Executors, con el tamaño del subproceso central cambiado de 0 a 20).

        return new ThreadPoolExecutor(20, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
Michael Krussel
fuente
4

Interesante pregunta.

Yo recomendaría en contra newCachedThreadPool. Generará tantos hilos como sea necesario sin ningún límite superior. ¡Es malo!

El enfoque sugerido por Michael parece bueno. Use ThreadPoolExecutory use un número con el que se sienta cómodo como el tamaño del grupo principal. Establezca el número máximo de subprocesos en algo que desea tolerar (o su servidor puede manejar).

Tenga en cuenta que no hay prácticamente nada que pueda hacer una vez que agote los recursos (la cola está llena y el número máximo de subprocesos está funcionando). En ese caso, puede hacer una de las dos cosas: dejar nuevas conexiones o aplicar contrapresión (no acepte nuevos trabajos bloqueando). TPE por defecto arroja RejectedExecutionExceptioncuando está lleno, pero es fácil de implementar el comportamiento de bloqueo. De hecho, aquí hay una implementación de código abierto de BlockingThreadPoolExecutor .

duendecillo
fuente
2

En cuanto a la RejectedExecutionException:

En lugar de un BlockingThreadPoolExecutor, simplemente podemos configurar el RejectedExecutionHandler en el ThreadPoolExecutor para usar el controlador CallerRunPolicy .

silmarx
fuente
0

Creo que usar un contenedor sobre un ThreadPoolExecutor es una buena manera de hacerlo. Un contenedor para que pueda exponer algo de inicialización (como un nombre de grupo, número de subprocesos, etc.) y un método para agregar una tarea (Ejecutable) a un grupo realizado anteriormente con uno de sus métodos de inicio.

El contenedor puede cambiar qué grupo usa sin afectar otro código, además puede exponer otros métodos como el número de subprocesos, auditorías (antes / después de la tarea) de manera consistente

También puede implementar su propia fábrica de subprocesos para su grupo, que puede tener un nombre personalizado, prioridad y, como mínimo, conectar un UncaughtExceptionHandler para que pueda registrar cualquier error.

en mi envoltorio de piscina tenemos métodos como

public static boolean queqeAdd(String poolName, int coreSize, int maxSize, boolean usePriorityQ, String threadNamePrefix, int timeOutSeconds) {...}
public static void execute(String poolName, Runnable command, Integer priority){...}
public static long tasksCount(String poolName) 
public static long tasksCompletedCount(String poolName) 
public static int clearPoolRequest(String poolName, boolean intrpt) 
public static int shutdownPoolRequest(String poolName) 
public static void executeAll(String poolName, List<Runnable> lst) 
tgkprog
fuente