[Alta concurrencia] ¿Cuáles son las formas de crear un grupo de subprocesos desde la perspectiva del código fuente?

Hola a todos, soy Glacier~~

En el campo de alta concurrencia de Java, los grupos de subprocesos siempre han sido un tema ineludible. Algunos zapatos de niños han estado usando grupos de subprocesos, pero la forma de crear grupos de subprocesos solo se interpone en el uso de la clase de herramienta Ejecutores, entonces, ¿cuáles son las formas de crear grupos de subprocesos? Echemos un vistazo más de cerca a cómo crear un grupo de subprocesos a partir del código fuente de la creación de un grupo de subprocesos.

Cree un grupo de subprocesos utilizando la clase de utilidad Executors

Al crear un grupo de subprocesos, los principiantes utilizan más la clase de herramienta Ejecutores, y usar esta clase de herramienta para crear un grupo de subprocesos es muy simple. No necesita prestar demasiada atención a los detalles del grupo de subprocesos, solo necesita para pasar los parámetros necesarios. La clase de utilidad Executors proporciona varios métodos para crear grupos de subprocesos, como se muestra a continuación.

  • Executors.newCachedThreadPool: Cree un grupo de subprocesos almacenable en caché. Si el tamaño del grupo de subprocesos excede la necesidad, puede reciclar de manera flexible los subprocesos inactivos. Si no hay subprocesos reciclables, cree un nuevo subproceso
  • Executors.newFixedThreadPool: cree un grupo de subprocesos de longitud fija, que puede controlar la cantidad máxima de subprocesos simultáneos, y el exceso de subprocesos esperará en la cola
  • Executors.newScheduledThreadPool: cree un grupo de subprocesos de longitud fija para admitir la ejecución de tareas programadas y periódicas
  • Executors.newSingleThreadExecutor: cree un grupo de subprocesos de un solo subproceso, use un subproceso de trabajo único para ejecutar tareas y asegúrese de que todas las tareas se ejecuten en el orden especificado (primero en entrar, primero en salir o prioridad)
  • Executors.newSingleThreadScheduledExecutor: cree un grupo de subprocesos de un solo subproceso que admita la ejecución de tareas programadas y periódicas
  • Executors.newWorkStealingPool: crea un grupo de subprocesos de robo de trabajo con nivel de paralelismo

Entre ellos, el método Executors.newWorkStealingPool es un nuevo método para crear un grupo de subprocesos en Java 8. Puede establecer el nivel de paralelismo para el grupo de subprocesos y tiene mayor concurrencia y rendimiento. Además de este método, otros métodos para crear grupos de subprocesos esencialmente llaman al constructor de la clase ThreadPoolExecutor.

Por ejemplo, podemos usar el siguiente código para crear un grupo de subprocesos.

Executors.newWorkStealingPool();
Executors.newCachedThreadPool();
Executors.newScheduledThreadPool(3);
复制代码

Cree un grupo de subprocesos utilizando la clase ThreadPoolExecutor

En cuanto a la estructura del código, la clase ThreadPoolExecutor hereda de AbstractExecutorService, es decir, la clase ThreadPoolExecutor tiene todas las funciones de la clase AbstractExecutorService.

Dado que la mayoría de los grupos de subprocesos creados en la clase de herramientas Executors llaman al constructor de la clase ThreadPoolExecutor, también podemos llamar directamente al constructor de la clase ThreadPoolExecutor para crear un grupo de subprocesos en lugar de usar la clase de herramientas Executors. A continuación, echemos un vistazo al constructor de la clase ThreadPoolExecutor.

Todos los constructores de la clase ThreadPoolExecutor se muestran a continuación.

public ThreadPoolExecutor(int corePoolSize,
			      int maximumPoolSize,
			      long keepAliveTime,
			      TimeUnit unit,
			     BlockingQueue<Runnable> workQueue) {
	this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
		 Executors.defaultThreadFactory(), defaultHandler);
}

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

public ThreadPoolExecutor(int corePoolSize,
				int maximumPoolSize,
				long keepAliveTime,
			        TimeUnit unit,
				BlockingQueue<Runnable> workQueue,
				RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
	 Executors.defaultThreadFactory(), handler);
}

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;
}
复制代码

Como se puede ver en el código fuente del constructor de la clase ThreadPoolExecutor, el constructor finalmente llamado para crear un grupo de subprocesos es el siguiente.

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;
}
复制代码

Para conocer el significado y la función de cada parámetro en este método de construcción, puede consultar " Alta simultaneidad: un análisis del grupo de subprocesos y la clase ThreadPoolExecutor que tengo que decir ".

Puede crear un grupo de subprocesos llamando al constructor de la clase ThreadPoolExecutor usted mismo. Por ejemplo, podemos crear un grupo de subprocesos utilizando el siguiente formulario.

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                       60L, TimeUnit.SECONDS,
                       new SynchronousQueue<Runnable>());
复制代码

Cree un grupo de subprocesos utilizando la clase ForkJoinPool

En la clase de herramientas Executors de Java8, se agregan los siguientes métodos para crear grupos de subprocesos.

public static ExecutorService newWorkStealingPool(int parallelism) {
	return new ForkJoinPool
		(parallelism,
		 ForkJoinPool.defaultForkJoinWorkerThreadFactory,
		 null, true);
}

public static ExecutorService newWorkStealingPool() {
	return new ForkJoinPool
		(Runtime.getRuntime().availableProcessors(),
		 ForkJoinPool.defaultForkJoinWorkerThreadFactory,
		 null, true);
}
复制代码

Desde el código fuente, sí, en esencia, se llama a la clase constructora de la clase ForkJoinPool para crear un grupo de subprocesos y, desde la perspectiva de la estructura del código, la clase ForkJoinPool hereda de la clase abstracta AbstractExecutorService. A continuación, veamos el constructor de la clase ForkJoinPool.

public ForkJoinPool() {
	this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
		 defaultForkJoinWorkerThreadFactory, null, false);
}
 public ForkJoinPool(int parallelism) {
	this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}

public ForkJoinPool(int parallelism,
				ForkJoinWorkerThreadFactory factory,
				UncaughtExceptionHandler handler,
				boolean asyncMode) {
	this(checkParallelism(parallelism),
		 checkFactory(factory),
		 handler,
		 asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
		 "ForkJoinPool-" + nextPoolId() + "-worker-");
	checkPermission();
}

private ForkJoinPool(int parallelism,
				 ForkJoinWorkerThreadFactory factory,
				 UncaughtExceptionHandler handler,
				 int mode,
				 String workerNamePrefix) {
	this.workerNamePrefix = workerNamePrefix;
	this.factory = factory;
	this.ueh = handler;
	this.config = (parallelism & SMASK) | mode;
	long np = (long)(-parallelism); // offset ctl counts
	this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
复制代码

Al observar el código fuente, sabemos que el constructor de ForkJoinPool finalmente llama al siguiente constructor privado.

private ForkJoinPool(int parallelism,
				 ForkJoinWorkerThreadFactory factory,
				 UncaughtExceptionHandler handler,
				 int mode,
				 String workerNamePrefix) {
	this.workerNamePrefix = workerNamePrefix;
	this.factory = factory;
	this.ueh = handler;
	this.config = (parallelism & SMASK) | mode;
	long np = (long)(-parallelism); // offset ctl counts
	this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
复制代码

El significado de cada parámetro es el siguiente.

  • paralelismo: Nivel de concurrencia.
  • fábrica: el objeto de clase de fábrica que crea el subproceso.
  • handler:当线程池中的线程抛出未捕获的异常时,统一使用UncaughtExceptionHandler对象处理。
  • mode:取值为FIFO_QUEUE或者LIFO_QUEUE。
  • workerNamePrefix:执行任务的线程名称的前缀。

当然,私有构造方法虽然是参数最多的一个方法,但是其不会直接对外方法,我们可以使用如下方式创建线程池。

new ForkJoinPool();
new ForkJoinPool(Runtime.getRuntime().availableProcessors());
new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
复制代码

使用ScheduledThreadPoolExecutor类创建线程池

在Executors工具类中存在如下方法类创建线程池。

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
	return new DelegatedScheduledExecutorService
		(new ScheduledThreadPoolExecutor(1));
}

public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
	return new DelegatedScheduledExecutorService
		(new ScheduledThreadPoolExecutor(1, threadFactory));
}

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
	return new ScheduledThreadPoolExecutor(corePoolSize);
}

public static ScheduledExecutorService newScheduledThreadPool(
		int corePoolSize, ThreadFactory threadFactory) {
	return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
复制代码

从源码来看,这几个方法本质上调用的都是ScheduledThreadPoolExecutor类的构造方法,ScheduledThreadPoolExecutor中存在的构造方法如下所示。

public ScheduledThreadPoolExecutor(int corePoolSize) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue());
}

public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), threadFactory);
}

public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), handler);
}

public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory, RejectedExecutionHandler handler) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), threadFactory, handler);
}
复制代码

而从代码结构上看,ScheduledThreadPoolExecutor类继承自ThreadPoolExecutor类,本质上还是调用ThreadPoolExecutor类的构造方法,只不过此时传递的队列为DelayedWorkQueue。我们可以直接调用ScheduledThreadPoolExecutor类的构造方法来创建线程池,例如以如下形式创建线程池。

new ScheduledThreadPoolExecutor(3)
复制代码

好了,今天就到这儿吧,我是冰河,我们下期见~~

Supongo que te gusta

Origin juejin.im/post/7101855019565056031
Recomendado
Clasificación