Explicar el papel del grupo de subprocesos y cómo usar el grupo de subprocesos en Java

Las aplicaciones del lado del servidor (como bases de datos y servidores web) necesitan procesar solicitudes de clientes de alta simultaneidad y consumo corto, por lo que la creación frecuente de subprocesos necesarios para procesar estas solicitudes es una operación que consume muchos recursos. El método convencional consiste en crear un nuevo hilo para una nueva solicitud, aunque este método parece fácil de implementar, tiene importantes desventajas. Crear un nuevo hilo para cada solicitud tomará más tiempo y más recursos del sistema al crear y destruir hilos. Por lo tanto, una JVM que crea demasiados subprocesos al mismo tiempo puede dar lugar a una memoria del sistema insuficiente, lo que requiere limitar el número de subprocesos a crear, es decir, se debe utilizar el grupo de subprocesos.

1. ¿Qué es un grupo de subprocesos en Java?

La tecnología de grupo de subprocesos es la tecnología de reutilización de subprocesos, que utiliza el subproceso creado previamente para realizar la tarea actual y proporciona una solución al problema de la sobrecarga del ciclo de subprocesos y los conflictos de recursos. Debido a que el hilo ya existe cuando llega la solicitud, se elimina el retraso causado por el proceso de creación del hilo y la aplicación puede responder más rápido.

  • Java proporciona un marco ejecutor centrado en la interfaz Executor y sus subinterfaces ExecutorService y ThreadPoolExecutor . Al usar Executor, solo necesita implementar la interfaz Runnable para completar la tarea del hilo y entregársela al ejecutor para su ejecución.
  • Encapsule el grupo de subprocesos por usted y enfoque sus tareas de programación en la realización de tareas específicas, en lugar del mecanismo de implementación de subprocesos.
  • Para usar el grupo de subprocesos, primero creamos un objeto ExecutorService y luego le pasamos un conjunto de tareas. La clase ThreadPoolExcutor puede establecer la inicialización del grupo de subprocesos y la capacidad máxima de subprocesos.

La figura anterior muestra que la inicialización del grupo de subprocesos tiene 3 subprocesos y hay 5 objetos de tarea para ejecutar en la cola de tareas.

Método del grupo de subprocesos del ejecutor | Método | Descripción | | --- | --- | | newFixedThreadPool (int) | Crea un grupo de subprocesos con un número fijo de subprocesos, el parámetro int indica el número de subprocesos en el grupo de subprocesos | | newCachedThreadPool () | Crear un grupo de subprocesos almacenables en caché, que puede recuperar de manera flexible los subprocesos inactivos. Si no hay ningún hilo inactivo, cree un nuevo hilo para procesar la tarea. | | newSingleThreadExecutor () | Crea un grupo de subprocesos de un solo subproceso, solo utilizará un solo subproceso de trabajo para realizar tareas | | newScheduledThreadExecutor | Crea un grupo de subprocesos de longitud fija, admite el tiempo y la ejecución de tareas periódicas |

En el caso de un grupo de subprocesos fijo, si el ejecutor actualmente ejecuta todos los subprocesos, las tareas pendientes se colocarán en la cola y se ejecutarán cuando los subprocesos estén inactivos.

Dos, ejemplo de grupo de subprocesos

En el siguiente contenido, presentaremos el ejecutor del grupo de subprocesos.

Pasos a seguir para crear un grupo de subprocesos para manejar tareas

  1. Crear un objeto de tarea (implementar la interfaz Runnable) para ejecutar una lógica de tarea específica
  2. Utilice Ejecutores para crear un grupo de subprocesos ExecutorService
  3. Entregue el objeto de la tarea que se ejecutará a ExecutorService para el procesamiento de la tarea
  4. Detener el grupo de subprocesos del ejecutor
//第一步: 创建一个任务对象(实现Runnable接口),用于执行具体的任务逻辑 (Step 1) 
class Task implements Runnable  {
    private String name;

    public Task(String s) {
        name = s;
    }

    // 打印任务名称并Sleep 1秒
    // 整个处理流程执行5次
    public void run() {
        try{
            for (int i = 0; i<=5; i++) {
                if (i==0) {
                    Date d = new Date();
                    SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
                    System.out.println("任务初始化" + name +" = " + ft.format(d));
                    //第一次执行的时候,打印每一个任务的名称及初始化的时间
                }
                else{
                    Date d = new Date();
                    SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
                    System.out.println("任务正在执行" + name +" = " + ft.format(d));
                    // 打印每一个任务处理的执行时间
                }
                Thread.sleep(1000);
            }
            System.out.println("任务执行完成" + name);
        }  catch(InterruptedException e)  {
            e.printStackTrace();
        }
    }
}

Caso de prueba

public class ThreadPoolTest {
    // 线程池里面最大线程数量
    static final int MAX_SIZE = 3;

    public static void main (String[] args) {
        // 创建5个任务
        Runnable r1 = new Task("task 1");
        Runnable r2 = new Task("task 2");
        Runnable r3 = new Task("task 3");
        Runnable r4 = new Task("task 4");
        Runnable r5 = new Task("task 5");

        // 第二步:创建一个固定线程数量的线程池,线程数为MAX_SIZE
        ExecutorService pool = Executors.newFixedThreadPool(MAX_SIZE);

        // 第三步:将待执行的任务对象交给ExecutorService进行任务处理
        pool.execute(r1);
        pool.execute(r2);
        pool.execute(r3);
        pool.execute(r4);
        pool.execute(r5);

        // 第四步:关闭线程池
        pool.shutdown();
    }
} 

Resultado de ejecución de ejemplo

任务初始化task 1 = 05:25:55
任务初始化task 2 = 05:25:55
任务初始化task 3 = 05:25:55
任务正在执行task 3 = 05:25:56
任务正在执行task 1 = 05:25:56
任务正在执行task 2 = 05:25:56
任务正在执行task 1 = 05:25:57
任务正在执行task 3 = 05:25:57
任务正在执行task 2 = 05:25:57
任务正在执行task 3 = 05:25:58
任务正在执行task 1 = 05:25:58
任务正在执行task 2 = 05:25:58
任务正在执行task 2 = 05:25:59
任务正在执行task 3 = 05:25:59
任务正在执行task 1 = 05:25:59
任务正在执行task 1 = 05:26:00
任务正在执行task 2 = 05:26:00
任务正在执行task 3 = 05:26:00
任务执行完成task 3
任务执行完成task 2
任务执行完成task 1
任务初始化task 5 = 05:26:01
任务初始化task 4 = 05:26:01
任务正在执行task 4 = 05:26:02
任务正在执行task 5 = 05:26:02
任务正在执行task 4 = 05:26:03
任务正在执行task 5 = 05:26:03
任务正在执行task 5 = 05:26:04
任务正在执行task 4 = 05:26:04
任务正在执行task 4 = 05:26:05
任务正在执行task 5 = 05:26:05
任务正在执行task 4 = 05:26:06
任务正在执行task 5 = 05:26:06
任务执行完成task 4
任务执行完成task 5

Como se muestra en el resultado de la ejecución del programa, la tarea 4 o la tarea 5 se ejecuta solo cuando el subproceso en el grupo queda inactivo. Antes de eso, las tareas adicionales se colocarán en la cola para ser ejecutadas.

El grupo de subprocesos realiza las tres primeras tareas, y los subprocesos en el grupo de subprocesos se reclaman y quedan vacantes antes de procesar las tareas 4 y 5

Una de las principales ventajas de usar este método de grupo de subprocesos es que si desea procesar 10,000 solicitudes a la vez, pero no desea crear 10,000 subprocesos, para evitar el tiempo de inactividad causado por el uso excesivo de los recursos del sistema. Puede utilizar este método para crear un grupo de subprocesos que contenga 500 subprocesos y puede enviar 500 solicitudes al grupo de subprocesos. ThreadPool creará hasta 500 hilos en este momento, procesando 500 solicitudes a la vez. Una vez que se completa el proceso de cualquier hilo, ThreadPool asignará internamente la solicitud 501 a ese hilo y continuará realizando la misma operación en todas las solicitudes restantes. En el caso de recursos del sistema relativamente limitados, el grupo de subprocesos es una solución eficaz para garantizar el funcionamiento estable del programa.

Tres, el uso de consideraciones y ajustes del grupo de subprocesos

  1. Interbloqueo: aunque puede producirse un interbloqueo en cualquier programa multiproceso, el grupo de subprocesos presenta otro caso de interbloqueo, en el que todos los subprocesos de ejecución están esperando el resultado de ejecución de un subproceso bloqueado en la cola, lo que hace que el subproceso no pueda continuar la ejecución.
  2. Fuga de subprocesos: si el subproceso del grupo de subprocesos no regresa correctamente cuando se completa la tarea, se producirá una fuga de subprocesos. Por ejemplo, si un subproceso genera una excepción y la clase de grupo no detecta esta excepción, el subproceso saldrá de forma anormal y el tamaño del grupo de subprocesos se reducirá en uno. Si esta situación se repite varias veces, el grupo de subprocesos eventualmente se vaciará y no se podrán utilizar subprocesos para realizar otras tareas.
  3. Rotación frecuente de subprocesos: si el tamaño del grupo de subprocesos es muy grande, el cambio de contexto entre subprocesos desperdiciará mucho tiempo. Entonces, en el caso de que los recursos del sistema lo permitan, no es que cuanto mayor sea el grupo de subprocesos, mejor.

Optimización del tamaño del grupo de subprocesos : el tamaño óptimo del grupo de subprocesos depende del número de procesadores disponibles y de la naturaleza de las tareas que se van a procesar. Para tareas con uso intensivo de CPU, asumiendo que el sistema tiene N núcleos de procesamiento lógico, un tamaño máximo de grupo de subprocesos de N o N + 1 logrará la máxima eficiencia. Para tareas intensivas de E / S, debe considerar la relación entre el tiempo de espera (W) de la solicitud y el tiempo de procesamiento del servicio (S). El tamaño máximo del grupo de subprocesos es N * (1+ W / S). para lograr la máxima eficiencia.

No utilice el resumen anterior de manera dogmática. Debe configurar y ajustar de manera flexible de acuerdo con el tipo de procesamiento de la tarea de su aplicación, y los experimentos de prueba son indispensables.

Bienvenido a seguir mi blog, hay muchas colecciones boutique.

  • Este artículo se reproduce con una indicación de la fuente (se debe adjuntar la conexión y el texto no se puede reproducir únicamente): Blog de Letter Brother .

Si crees que es útil para ti, ¡dale me gusta y compártelo! ¡Tu apoyo es mi inagotable motivación creativa! . Además, el autor ha publicado el siguiente contenido de alta calidad recientemente y espero su atención.

Supongo que te gusta

Origin blog.csdn.net/hanxiaotongtong/article/details/112598976
Recomendado
Clasificación