===== Directorio de artículos =====
- problema
- Grupo de subprocesos ThreadPoolExecutor
- Implementación de arquitectura
- Cómo usar el grupo de subprocesos
- Siete parámetros del grupo de subprocesos
- Hablar sobre el principio de funcionamiento subyacente del grupo de subprocesos (énfasis)
- Cómo verificar la cantidad de núcleos de CPU
- Referencia
problema
¿Dónde están las ventajas y desventajas de los grupos de subprocesos?
¿Cuál es el principio de implementación subyacente del grupo de subprocesos?
¿Cómo hacer un buen uso del grupo de subprocesos en el desarrollo diario?
¿Qué grupo de subprocesos se utiliza realmente?
Grupo de subprocesos ThreadPoolExecutor
Concepto
El trabajo realizado por el grupo de subprocesos es principalmente para controlar la cantidad de subprocesos en ejecución. Durante el procesamiento, las tareas se agregan a la cola , y luego estas tareas se inician después de que se crea el subproceso. Si se excede el número máximo , el exceso de subprocesos esperará en línea y esperará otros subprocesos. Una vez completada la ejecución, la tarea se saca de la cola para su ejecución.
Ventajas
Sus principales características son: reutilización de hilos, controlar el número máximo de concurrencia y gestionar hilos.
- Reutilización de subprocesos: no es necesario conservar nuevos subprocesos, reutilizar subprocesos que se han creado para reducir la sobrecarga de creación y destrucción de subprocesos y ahorrar recursos del sistema.
- Mejorar la velocidad de respuesta: cuando se alcanza la tarea, no es necesario crear un nuevo hilo, utilice directamente el hilo del grupo de hilos.
- Gestión de subprocesos: puedes controlar el número máximo de subprocesos simultáneos, controlar la creación de subprocesos, etc.
Sistema
Executor
→ ExecutorService
→ AbstractExecutorService
→ ThreadPoolExecutor
. ThreadPoolExecutor
Es la clase principal creada por el grupo de subprocesos. Al igual Arrays
que las Collections
herramientas, Executor
también tienen sus propias herramientas Executors
.
Implementación de arquitectura
El grupo de subprocesos en Java se implementa a través del marco Executor, que utiliza las clases Executor, Executors, ExecutorService y ThreadPoolExecutor.
Cómo usar el grupo de subprocesos
Tres formas comunes de crear grupos de subprocesos
newFixedThreadPool : LinkedBlockingQueue
implementación de uso , grupo de subprocesos de longitud fija.
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor : LinkedBlockingQueue
Implementación de uso , un grupo tiene solo un hilo.
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool : SynchronousQueue
Implementación de uso , grupo de subprocesos de longitud variable.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
Siete parámetros del grupo de subprocesos
int corePoolSize,核心线程
int maximumPoolSize,非核心线程
long keepAliveTime,时间
TimeUnit unit,时间单位
BlockingQueue<Runnable> workQueue,队列
ThreadFactory threadFactory,线程工厂
RejectedExecutionHandler handler 拒绝策略
formar
parámetro | significado |
---|---|
corePoolSize | Número de subprocesos principales residentes en el grupo de subprocesos |
maximumPoolSize | Número máximo de subprocesos que se pueden acomodar |
keepAliveTime | Tiempo de supervivencia del hilo inactivo |
unidad | Unidad de tiempo de supervivencia |
workQueue | Una cola que almacena tareas enviadas pero no ejecutadas |
threadFactory | Clase de fábrica para crear hilos |
manipulador | Política de rechazo después de que la cola de espera esté llena |
Notas de método
corePoolSize: el número de subprocesos que se mantendrán en el grupo, incluso si están inactivos, a menos que allowCoreThreadTimeOut esté establecido como
maximumPoolSize: el número máximo de subprocesos que se permitirán en el grupo
keepAliveTime: cuando el número de subprocesos es mayor que el núcleo, este es el tiempo máximo que el exceso de subprocesos inactivos esperará nuevas tareas antes de terminar.
unit: la unidad de tiempo para el argumento
keepAliveTime workQueue: la cola que se usa para mantener las tareas antes de que se ejecuten. Esta cola contendrá solo las tareas ejecutables enviadas por el método de ejecución.
threadFactory: la fábrica que se usa cuando el ejecutor crea un nuevo
controlador de subprocesos : el controlador que se usa cuando la ejecución está bloqueada porque se alcanzan los límites del subproceso y las capacidades de la cola
Código
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
Comprensión : los parámetros de creación del grupo de subprocesos son como un banco .
corePoolSize
Al igual que la " ventanilla de servicio " del banco , por ejemplo, hoy en día hay 2 cajeros que atienden las solicitudes (tareas) de los clientes . Si hay más de 2 clientes, los nuevos clientes esperarán en el área de espera (cola de espera workQueue
). Cuando el área de espera está llena, la " ventana de horas extras " debe abrirse en este momento para permitir que los otros 3 cajeros trabajen horas extras. En este momento, la ventana máximamaximumPoolSize
es de 5. Si todas las ventanas están abiertas y la zona de espera aún está llena, se debe activar la " estrategia de rechazo " en este momento para handler
decirle a la afluencia de clientes que no ingresen, que está llena. Dado que no hay más afluencia de nuevos clientes, se terminan más clientes y la ventana se vuelve inactiva. En este momento, al keepAlivetTime
cancelar las 3 "ventanas de tiempo extra" adicionales, restaure a 2 "ventanas de servicio".
Proceso
Si el número de subprocesos en ejecución es menor que corePoolSize, cree un subproceso central; si es mayor o igual que corePoolSize, colóquelo en la cola de espera.
Si la cola de espera está llena, pero el número de subprocesos en ejecución es menor que maximumPoolSize, cree un subproceso no central; si es mayor o igual que maximumPoolSize, inicie la estrategia de rechazo.
Cuando un subproceso no tiene nada que hacer durante un período de keepAliveTime, si el número de subprocesos en ejecución es mayor que corePoolSize, se cierra el subproceso no principal.
Estrategia de rechazo del grupo de subprocesos
Cuando la cola de espera está llena, se alcanza el número máximo de subprocesos y llega una nueva tarea, es necesario iniciar la estrategia de rechazo. JDK proporciona cuatro estrategias de rechazo, respectivamente.
- AbortPolicy : la política predeterminada, que lanza directamente
RejectedExecutionException
una excepción para evitar que el sistema se ejecute normalmente. - CallerRunsPolicy : no lanza una excepción ni finaliza la tarea, pero devuelve la tarea a la persona que llama.
- DiscardOldestPolicy : descarte la tarea de espera más larga en la cola y luego agregue la tarea actual a la cola e intente enviar la tarea nuevamente.
- DiscardPolicy : descarte la tarea directamente sin ningún procesamiento.
¿Qué grupo de subprocesos se utiliza en la producción real (énfasis)?
Imagen de la versión de Songshan del manual de desarrollo de Ali Java
¡No se necesitan longitudes únicas, variables y fijas ! La razón es que, FixedThreadPool
y SingleThreadExecutor
se usa la capa inferior LinkedBlockingQueue
, se logra la longitud máxima de la cola Integer.MAX_VALUE
, obviamente conduce a OOM. Por lo tanto, en la producción real, generalmente pasa ThreadPoolExecutor
7 parámetros y personaliza el grupo de subprocesos.
ExecutorService threadPool=new ThreadPoolExecutor(2,5,
1L,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
Selección de parámetros de grupo de subprocesos personalizados
Tareas intensivas en CPU
Para tareas con uso intensivo de CPU, el número máximo de subprocesos es el número de subprocesos de CPU + 1.
El uso intensivo de CPU significa que la tarea requiere muchos cálculos sin bloqueo. La CPU ha estado funcionando a toda velocidad.
Las tareas intensivas de CPU solo se pueden acelerar en una verdadera
CPU de varios núcleos (a través de múltiples subprocesos) y en una CPU de un solo núcleo (¿tragedia? ), no importa cuántos subprocesos múltiples simulados abra, la tarea no se puede acelerar, porque la potencia informática total de la CPU es solo eso.
Las tareas intensivas en CPU configuran la menor cantidad de subprocesos posible:
fórmula general: número de núcleos de CPU + 1 grupo de subprocesos
Tareas intensivas en IO
Para tareas intensivas en E / S, asigne tantos puntos como sea posible, que puede ser el número de subprocesos de CPU * 2 o el número de subprocesos de CPU / (factor de bloqueo 1).
Experiencia de una gran fábrica
Intensivo en IO, es decir, la tarea requiere mucho O, es decir, mucho bloqueo.
La ejecución de tareas con un uso intensivo de 10 en un solo subproceso dará como resultado el desperdicio de una gran cantidad de potencia informática de la CPU desperdiciada en la espera.
Por lo tanto, el uso de subprocesos múltiples en tareas con un uso intensivo de IO puede acelerar enormemente la ejecución del programa. Incluso en una CPU de un solo núcleo, esta aceleración es principalmente Utilice el tiempo de bloqueo perdido.
Cuando IO es intensivo, la mayoría de los subprocesos están bloqueados, por lo que debe configurar el número de subprocesos.
Fórmula de referencia: número de núcleo de CPU / coeficiente de bloqueo 1. El
coeficiente de bloqueo está entre 0,8 y 09. Por
ejemplo, CPU de 8 núcleos: 8 /(1-0.9)=80 Hilos
Hablar sobre el principio de funcionamiento subyacente del grupo de subprocesos (énfasis)
El siguiente contenido es muy importante, el siguiente contenido es muy importante, el siguiente contenido es muy importante
1. Después de crear el grupo de subprocesos, espere la solicitud de tarea enviada.
2. Cuando se llama al método execute (para agregar una tarea de solicitud, el grupo de subprocesos hará los siguientes juicios
2.1 Si el número de subprocesos en ejecución es menor que corePoolSize, entonces cree inmediatamente un subproceso para ejecutar la tarea;
2.2 Si el número de subprocesos en ejecución es mayor o igual que corePoolSize, entonces Ponga esta tarea en la cola
2.3 Si la cola está llena en este momento y la cantidad de subprocesos en ejecución es menor que maximumPoolSize, entonces todavía tiene que crear subprocesos no centrales para ejecutar esta tarea inmediatamente
2.4 Si la cola está llena y la cantidad de subprocesos en ejecución es mayor o igual a maximumPoolSize , Luego, el grupo de subprocesos iniciará la estrategia de rechazo de saturación para ejecutarse .
3. Cuando un subproceso completa la tarea, tomará la siguiente tarea de la cola para su ejecución.
4. Cuando un subproceso no tiene nada que hacer durante más de cierto tiempo (keepAlive Time) En ese momento, el grupo de subprocesos juzgará:
si el número de subprocesos actualmente en ejecución es mayor que corePoolSize, este subproceso se detendrá.
Por lo tanto, después de que se completen todas las tareas del grupo de subprocesos, eventualmente se reducirá al tamaño de corePoolsize .
Cómo verificar la cantidad de núcleos de CPU
Botón derecho del ratón, ¡¡¡No !!!
System.out.println(Runtime.getRuntime().availableProcessors());
Referencia
Grupo de subprocesos de programación concurrente de Java ThreadPoolExecutor utiliza
Ali boss para que comprenda el principio subyacente del grupo de subprocesos
JVM-JUC-Core
Ali manual de desarrollo de Java Songshan version.pdf