Un breve análisis del principio de funcionamiento y la API del grupo de subprocesos ThreadPool de JAVA de alta concurrencia (JUC)

Esta vez nos referimos al grupo de subprocesos de JUC . Para ThreadPool, podemos entender que se han creado un montón de subprocesos para nosotros, y luego dejar que estos subprocesos hagan lo que especifiquemos.
Primero mire el diagrama de herencia:
Inserte la descripción de la imagen aquí
Ejecutores tres métodos para crear hilos:

ExecutorService threadPool = Executors.newFixedThreadPool(5);	//固定容量
ExecutorService threadPool = Executors.newSingleThreadExecutor(); 	//单例的、单个线程的线程池
ExecutorService threadPool = Executors.newCachedThreadPool(); 	//缓存的 即超出就自动创建线程的

A continuación, explique la diferencia entre estos tres:

Primero miramos el primer grupo de subprocesos de capacidad fijaExecutors.newFixedThreadPool(5); :
primero miramos el código:

/**
 * 主要特点:线程复用;控制最大并发数;管理线程。
 *
 * @author Cocowwy
 * @create 2020-05-05-20:20
 * Executor/ExecutorServic(Interface)
 * Executors  线程池的工具类
 */
public class MyThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
        //一池五个受理线程
        ExecutorService threadPool = Executors.newFixedThreadPool(5);  //看源码是LinkedBlockingQueue<Runnable>()
        try {
    
    
            //模拟10个用户办理业务,但是只有5个受理窗口
            for (int i = 0; i < 10; i++) {
    
    
                threadPool.execute(() -> {
    
    
                    System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");
                });
                Thread.sleep(400);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            threadPool.shutdown(); //关闭线程池
        }
    }

}

El resultado es el siguiente:

Luego agregamos un código que el hilo duerme por un rato.

public class MyThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
        //一池五个受理线程
        ExecutorService threadPool = Executors.newFixedThreadPool(5);  //看源码是LinkedBlockingQueue<Runnable>()
        try {
    
    
            //模拟10个用户办理业务,但是只有5个受理窗口
            for (int i = 0; i < 10; i++) {
    
    
                threadPool.execute(() -> {
    
    
                    System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");
                });
                Thread.sleep(400);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            threadPool.shutdown(); //关闭线程池
        }
    }

}

Inserte la descripción de la imagen aquí
Aquí podemos ver que cada negocio ha sido procesado de forma ordenada. Se puede ver que este es un grupo de subprocesos con un tamaño fijo, y los subprocesos se toman de este grupo de subprocesos cada vez.

Este es el segundo grupo de subprocesos singleton :ExecutorService threadPool = Executors.newSingleThreadExecutor(); //一池1个受理线程

public class MyThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
//        ExecutorService threadPool = Executors.newFixedThreadPool(5);  //一池五个受理线程,看源码是LinkedBlockingQueue<Runnable>()
        ExecutorService threadPool = Executors.newSingleThreadExecutor();  //一池1个受理线程

        try {
    
    
            //模拟10个用户办理业务,但是只有5个受理窗口
            for (int i = 0; i < 10; i++) {
    
    
                threadPool.execute(() -> {
    
    
              System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");
                });
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            threadPool.shutdown(); //关闭线程池
        }
    }
}

Inserte la descripción de la imagen aquí
Podemos ver que un hilo siempre ha aceptado negocios.

El siguiente es el tercer grupo de subprocesos : ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N个受理线程 可扩展的
Siguiente código:

public class MyThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
//        ExecutorService threadPool = Executors.newFixedThreadPool(5);  //一池五个受理线程,看源码是LinkedBlockingQueue<Runnable>()
//        ExecutorService threadPool = Executors.newSingleThreadExecutor();  //一池1个受理线程
         ExecutorService threadPool = Executors.newCachedThreadPool();  //一池N个受理线程

        try {
    
    
            //模拟10个用户办理业务,但是只有5个受理窗口
            for (int i = 0; i < 10; i++) {
    
    
                threadPool.execute(() -> {
    
    
                    try {
    
    
                        Thread.sleep(400);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");
                });
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            threadPool.shutdown(); //关闭线程池
        }
    }

}

Primero observe el efecto:
Inserte la descripción de la imagen aquí
en el código anterior, podemos encontrar que el hilo tomado del grupo de hilos durmió durante 0.4s, pero podemos encontrar que se crean más hilos, por lo que podemos encontrar eso cuando hay demasiadas solicitudes Se crearán hilos.
Lo anterior es una API simple para el grupo de subprocesos.

A continuación, eche un vistazo al código fuente del grupo de subprocesos:
primero haga clic en el código fuente de newFixedThreadPool () para ver:
Inserte la descripción de la imagen aquí
Luego haga clic en el código fuente de newSingleThreadExecutor () para ver:
Inserte la descripción de la imagen aquí
Luego haga clic en el código fuente de newCachedThreadPool () para ver:


En resumen, lo que se devuelve en realidad es solo uno ThreadPoolExecutor(ver el diagrama de herencia), utilizando diferentes parámetros pasados ​​por el constructor, y también podemos encontrar que la capa inferior es una cola de bloqueo.
Al mismo tiempo, muestra que también podemos crear un grupo de subprocesos a través de ThreadPoolExecutor`. Executors es solo una clase de herramienta para crear grupos de subprocesos, y en realidad devuelve ThreadPoolExecutor.

Luego continuamos apuntando ThreadPoolExecutor:
Inserte la descripción de la imagen aquíLuego haga clic en esto, podemos ver que tiene siete parámetros:
Inserte la descripción de la imagen aquí
La figura a continuación es una explicación de estos siete parámetros:
Inserte la descripción de la imagen aquí
A continuación , entenderemos los siete parámetros anteriores en combinación con la figura a continuación:
Primero mire el hilo El diagrama de principio de funcionamiento inferior del grupo: mirando
Inserte la descripción de la imagen aquí
la figura anterior y la comparación del análisis de parámetros, podemos saber que maximumPool contiene corePool , maximumPool representa el número máximo de hilos que se pueden poner y corePool representa el número residente de hilos, que puede entenderse como un banco con un máximo de 5 Hay dos ventanas de aceptación, pero solo dos se usan comúnmente, y el área de espera es equivalente a nuestra cola de bloqueo ( BlockingQueue ). Cuando nuestra cola de bloqueo está llena, sale la estrategia de rechazo de la manija , que equivale a un bloqueo en la puerta del banco. ¡El letrero dice que no se atenderán más asuntos! Luego, cuando los clientes casi terminan, la ventana adicional (la ventana expandida sobre la base de corePool) se cierra después del tiempo de keepAliveTime y se restaura a la ventana de aceptación de corePool .

A continuación, resumamos el flujo de trabajo del grupo de
subprocesos : primero, el grupo de subprocesos recibe tareas, primero juzga si el número de subprocesos principales está lleno y, si no está lleno, colócalos en la cola de bloqueo. Si la cola de bloqueo no está llena, estas tareas se colocan en la cola de bloqueo. Si está lleno, expanda el número de subprocesos al número máximo de subprocesos. Si el número máximo de subprocesos también está lleno, es nuestra política de rechazo. Estos son los cuatro pasos principales del grupo de subprocesos. ¡Recoja clientes, póngalos en la cola, expanda hilos y rechace estrategias!
También puedes ver esta imagen:
Inserte la descripción de la imagen aquí

¿Cómo lo configuramos en el desarrollo real?
Inserte la descripción de la imagen aquí
¿por qué?
Por ejemplo, antes de responder newSingleThreadExecutor(); ;y Executors.newCachedThreadPool( );crear el grupo de subprocesos, mire la fuente,

 	//这是Single的
	public static ExecutorService newSingleThreadExecutor() {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    }
    //点进去LinkedBlockQueue
        public LinkedBlockingQueue() {
    
    
        this(Integer.MAX_VALUE);
    }

   //这是Cahed的
    public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

Para newSingleThreadExecutor () ; la longitud de LinkedBlockQueue es Integer.MAX_VALUE , y
para newCachedThreadPool () , el valor de maximumPool es Integer.MAX_VALUE ! !
¡Ambos causarán excepciones OOM !

Después de hablar sobre los parámetros anteriores, echemos un vistazo al grupo de subprocesos personalizados:

public class MyThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
        //自定义线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,
                5,
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3), //不写的话默认也是Integer.MAX_VALUE
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());//默认的拒绝策略

        try {
    
    
            //模拟10个用户办理业务,但是只有5个受理窗口
            for (int i = 0; i < 9; i++) {
    
    
                threadPool.execute(() -> {
    
    
                    System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");
                });
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            threadPool.shutdown(); //关闭线程池
        }
    }

threadPool es nuestro grupo de subprocesos personalizado. Aquellos que se han conectado a los parámetros anteriores deben saber que la cantidad máxima de simultaneidad admitida por el grupo de subprocesos debe ser el tamaño del grupo máximo + Cola, es decir, 5 + 3 = 8, y será después de que se exceda el tamaño Error: java.util.concurrent.RejectedExecutionExceptionnegarse a ejecutar la excepción
Inserte la descripción de la imagen aquí
A continuación, veamos las cuatro principales estrategias de rechazo del grupo de subprocesos. La anterior es la estrategia de rechazo predeterminada del JDK :
Inserte la descripción de la imagen aquí
A continuación, veamos los resultados de las otras tres estrategias. Cambie la estrategia de rechazo del código anterior por la segunda new ThreadPoolExecutor.CallerRunsPolicy()
Inserte la descripción de la imagen aquí
. Tres new ThreadPoolExecutor.DiscardOldestPolicy():
Inserte la descripción de la imagen aquí
No se informa ningún error.
Cuarto new ThreadPoolExecutor.DiscardPolicy():

No se informa ningún error.
Las estrategias anteriores se heredan de la RejectedExecutionHandlerinterfaz.
Finalmente, cómo establecer el maximumPoolSize razonable,

System.out.println(Runtime.getRuntime().availableProcessors()); //8核

Generalmente se establece en el número de núcleos de CPU más 1.

Lo anterior es la explicación de este grupo de subprocesos. Si hay algo irrazonable, ¡deje un mensaje a continuación!

Supongo que te gusta

Origin blog.csdn.net/Pzzzz_wwy/article/details/106432430
Recomendado
Clasificación