Grupo de subprocesos múltiples de Java

Seis, grupo de subprocesos

1. Utilice las ventajas

  1. Reducir el consumo de recursos

    Puede reutilizar el hilo creado para reducir el consumo causado por la creación y destrucción del hilo

  2. Mejorar la velocidad de respuesta

    Cuando llega la tarea, se puede ejecutar inmediatamente sin esperar a que se cree el hilo

  3. Mejorar la capacidad de administración de subprocesos

    Thread es un recurso escaso, la creación infinita no solo consumirá recursos del sistema, sino que también reducirá la estabilidad del sistema. El uso de grupos de subprocesos se puede utilizar para una asignación, ajuste y supervisión uniformes

2. La creación de un grupo de subprocesos

por java.util.concurrent.ThreadPoolExecutorla creación de

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

corePoolSize: el número de subprocesos centrales

maximumPoolSize: el número máximo de subprocesos (incluido el número de subprocesos principales)

keepAliveTime: el tiempo de supervivencia (valor numérico) de los subprocesos no centrales. El tiempo máximo para que los subprocesos no centrales (estado inactivo) esperen la finalización de nuevas tareas (esperar nuevas tareas antes de finalizar)java.lang.Thread.State: WAITING (parking)

unidad: el tiempo de supervivencia de subprocesos no centrales (unidad)

workQueue: cola de tareas del hilo

threadFactory: Fábrica de métodos para generar hilos. Por ejemplo, la fábrica de hilos creada usando el método estático predeterminadojava.util.concurrent.Executors#defaultThreadFactory

handler: estrategia de rechazo de tareas de subprocesos. Por ejemplo, utilice la estrategia de ejecución de denegación predeterminadajava.util.concurrent.ThreadPoolExecutor.AbortPolicy

/* 会直接抛出异常 */
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    
    
    throw new RejectedExecutionException("Task " + r.toString() +
                                         " rejected from " +
                                         e.toString());
}

3. Método de trabajo

  1. Al ejecutar una tarea de subproceso, primero determine si se alcanza el número de subprocesos centrales (corePoolSize), si no se alcanza, se creará un nuevo subproceso para ejecutar la tarea del subproceso; de lo contrario, la tarea del subproceso se agregará a la cola de bloqueo (BlockingQueue)
  2. Cuando la cola de bloqueo esté llena y no se haya alcanzado el número máximo de subprocesos (maximumPoolSize), se creará un nuevo subproceso para realizar tareas de subprocesos
  3. Cuando se alcanza el número máximo de subprocesos, si es necesario ejecutar tareas de subprocesos, se ejecutará la estrategia de rechazo (controlador)
  4. Cuando los subprocesos adicionales (subprocesos no centrales) están inactivos y se alcanza el tiempo máximo de espera, se terminarán ( TERMINARÁN )

Nota: al crear un nuevo hilo, debe adquirir un bloqueo global

/**
 * Lock held on access to workers set and related bookkeeping.
 * While we could use a concurrent set of some sort, it turns out
 * to be generally preferable to use a lock. Among the reasons is
 * that this serializes interruptIdleWorkers, which avoids
 * unnecessary interrupt storms, especially during shutdown.
 * Otherwise exiting threads would concurrently interrupt those
 * that have not yet interrupted. It also simplifies some of the
 * associated statistics bookkeeping of largestPoolSize etc. We
 * also hold mainLock on shutdown and shutdownNow, for the sake of
 * ensuring workers set is stable while separately checking
 * permission to interrupt and actually interrupting.
 */
private final ReentrantLock mainLock = new ReentrantLock();


private boolean addWorker(Runnable firstTask, boolean core) {
    
    

    // ... ...

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
    
    
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
    
    
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
    
    
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
    
    
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
    
    
                mainLock.unlock();
            }
            if (workerAdded) {
    
    
                t.start();
                workerStarted = true;
            }
        }
    } finally {
    
    
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

Aunque puede utilizar la simultaneidad, es mejor utilizar bloqueos. Porque, por un lado, se puede garantizar la seguridad de los subprocesos, de modo que el grupo de subprocesos se ejecute de manera estable; por otro lado, algunas operaciones se simplifican (implementación del código fuente del grupo de subprocesos)

4. Mejores prácticas

  1. Configure razonablemente el número máximo de subprocesos
    • Tareas intensivas de CPU: Número de núcleos de CPU + 1 [Reducir la conmutación de subprocesos]
    • Tareas intensivas en IO [método de cálculo uno]: número de núcleo de CPU × 2
    • Tareas intensivas en IO [método de cálculo dos]: número de núcleo de la CPU / (coeficiente de bloqueo 1), el coeficiente de bloqueo está entre 0,8 y 0,9 [Aumentar el rendimiento]
  2. Configure correctamente el keepAliveTime de los subprocesos no centrales. Si hay muchas tareas por ejecutar y el tiempo de ejecución de la tarea es corto, puede aumentar este tiempo para mejorar la utilización del subproceso
  3. Configure el tamaño de la cola de bloqueo de manera razonable. Si es demasiado grande, no solo no se puede ejecutar la tarea, sino que también se pueden agotar los recursos de memoria
  4. Hay dos formas shutdownde cerrar el grupo de subprocesos: es solo cerrar el grupo de subprocesos, pero las tareas no terminadas aún se ejecutarán; shutdownNowes cerrar el grupo de subprocesos, pero las tareas no terminadas deben terminarse.

Supongo que te gusta

Origin blog.csdn.net/adsl624153/article/details/103865353
Recomendado
Clasificación