22. Ejecutor y grupo de hilos: ¿cómo crear el grupo de hilos correcto? -Herramientas de concurrencia

Un hilo es un objeto pesado, y se debe evitar la creación y destrucción frecuentes. El grupo de subprocesos proporcionado por el SDK de Java es diferente de otros recursos agrupados, y no proporciona métodos para aplicar subprocesos y liberar subprocesos.

1. El grupo de subprocesos es un modelo productor-consumidor

El consumidor del grupo de subprocesos es el productor, y el grupo de subprocesos en sí mismo es el consumidor. El siguiente código explica brevemente el principio del grupo de subprocesos:

//简化的线程池,仅用来说明工作原理
class MyThreadPool {
	//利用阻塞队列实现生产者-消费者模式
	BlockingQueue<Runnable> workQueue;
	//保存内部工作线程
	List<WorkerThread> threads = new ArrayList<>();

	// 构造方法
	MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {
		this.workQueue = workQueue;
		// 创建工作线程
		for (int idx = 0; idx < poolSize; idx++) {
			WorkerThread work = new WorkerThread();
			work.start();
			threads.add(work);
		}
	}

	// 提交任务
	void execute(Runnable command) {
		workQueue.put(command);
	}

	// 工作线程负责消费任务,并执行任务
	class WorkerThread extends Thread {
		public void run() { // (1)
			// 循环取任务并执行
			while (true) {
				Runnable task = workQueue.take();
				task.run();
			}
		}
	}
}

	/** 下面是使用示例 **/
	// 创建有界阻塞队列
	BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
	// 创建线程池
	MyThreadPool pool = new MyThreadPool(10, workQueue);
	// 提交任务
	pool.execute(()->{
	    System.out.println("hello");
	});

2. Cómo usar el grupo de subprocesos en Java

El núcleo es ThreadPoolExecutor , el constructor más complejo:

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue<Runnable> workQueue,
                    ThreadFactory threadFactory,
                    RejectedExecutionHandler handler) 
  • corePoolSize, que representa el número mínimo de subprocesos contenidos en el grupo de subprocesos;
  • maximumPoolSize, que representa el número máximo de subprocesos creados por el grupo de subprocesos;
  • keepAliveTime & unit, si un subproceso ha estado inactivo keepAliveTime & unit durante tanto tiempo, y el número de subprocesos en el grupo de subprocesos es mayor que corePoolSize, entonces el subproceso inactivo se reciclará;
  • workQueue, cola de trabajo, utilizada para almacenar hilos;
  • threadFactory: personalice cómo crear hilos, por ejemplo, asigne un nombre significativo al hilo;
  • manejador: estrategia de rechazo para tareas personalizadas. Existen cuatro estrategias:
    1. CallerRunsPolicy: el subproceso que envió la tarea realiza la tarea en sí.
    2. AbortPolicy: la política de rechazo predeterminada arrojará RejectedExecutionException.
    3. DiscardPolicy: descarta la tarea directamente sin ninguna excepción.
    4. DiscardOldestPolicy: descartar la tarea más antigua es descartar la tarea más antigua que ingresó en la cola de trabajo y luego agregar la nueva tarea a la cola de trabajo.

3. A qué prestar atención cuando se usa el grupo de subprocesos

La razón más importante por la que no se recomiendan los Ejecutores de fábrica estáticos del grupo de subprocesos es que muchos de los métodos proporcionados por los Ejecutores usan el LinkedBlockingQueue ilimitado de forma predeterminada. Las colas ilimitadas pueden conducir fácilmente a OOM en escenarios de alta carga, y OOM causará todas las solicitudes Tratamiento, este es un problema fatal. Por lo tanto, se recomienda utilizar colas limitadas .

La estrategia de rechazo predeterminada debe usarse con precaución. Si las tareas manejadas por el grupo de subprocesos son muy importantes, se recomienda personalizar su propia estrategia de rechazo; y en el trabajo real, la estrategia de rechazo personalizada a menudo se usa junto con la estrategia de degradación.

Aunque el grupo de subprocesos proporciona muchos métodos para el manejo de excepciones, la solución más segura y simple es capturar todas las excepciones y manejarlas según sea necesario. Puede consultar el código de ejemplo a continuación.

try {
  //业务逻辑
} catch (RuntimeException x) {
  //按需处理
} catch (Throwable x) {
  //按需处理
} 
97 artículos originales publicados · elogiados 3 · 10,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/qq_39530821/article/details/102713127
Recomendado
Clasificación