[High Concurrency] What are the ways to create a thread pool from the perspective of source code?

Hello everyone, I'm Glacier~~

In the high concurrency field of Java, thread pools have always been an inescapable topic. Some children's shoes have been using thread pools, but how to create thread pools only stays in the way of using the Executors tool class, so what are the ways to create thread pools? Let's take a closer look at how to create a thread pool from the source code of creating a thread pool.

Create a thread pool using the Executors utility class

When creating a thread pool, beginners use the tool class Executors the most, and using this tool class to create a thread pool is very simple. You don't need to pay too much attention to the details of the thread pool, you only need to pass in the necessary parameters. . The Executors utility class provides several methods for creating thread pools, as shown below.

  • Executors.newCachedThreadPool: Create a cacheable thread pool. If the size of the thread pool exceeds the need, it can flexibly recycle idle threads. If there are no recyclable threads, create a new thread
  • Executors.newFixedThreadPool: Create a fixed-length thread pool, which can control the maximum number of concurrent threads, and the excess threads will wait in the queue
  • Executors.newScheduledThreadPool: Create a fixed-length thread pool to support scheduled and periodic task execution
  • Executors.newSingleThreadExecutor: Create a single-threaded thread pool, use a unique worker thread to execute tasks, and ensure that all tasks are executed in the specified order (first-in, first-out or priority)
  • Executors.newSingleThreadScheduledExecutor: Create a single-threaded thread pool to support scheduled and periodic task execution
  • Executors.newWorkStealingPool: Create a work-stealing thread pool with parallelism level

Among them, the Executors.newWorkStealingPool method is a new method for creating a thread pool in Java 8. It can set the parallelism level for the thread pool and has higher concurrency and performance. In addition to this method, other methods of creating thread pools essentially call the constructor of the ThreadPoolExecutor class.

For example, we can use the following code to create a thread pool.

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

Create a thread pool using the ThreadPoolExecutor class

In terms of code structure, the ThreadPoolExecutor class inherits from AbstractExecutorService, that is to say, the ThreadPoolExecutor class has all the functions of the AbstractExecutorService class.

Since most of the thread pools created in the Executors tool class call the constructor of the ThreadPoolExecutor class, we can also directly call the constructor of the ThreadPoolExecutor class to create a thread pool instead of using the Executors tool class. Next, let's take a look at the constructor of the ThreadPoolExecutor class.

All constructors in the ThreadPoolExecutor class are shown below.

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

As can be seen from the source code of the constructor of the ThreadPoolExecutor class, the constructor finally called to create a thread pool is as follows.

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

For the meaning and function of each parameter in this construction method, you can refer to " High Concurrency - An Analysis of the Thread Pool and ThreadPoolExecutor Class that I Have to Say ".

You can create a thread pool by calling the constructor of the ThreadPoolExecutor class by yourself. For example, we can create a thread pool using the following form.

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

Create a thread pool using the ForkJoinPool class

In the Executors tool class of Java8, the following methods for creating thread pools are added.

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

From the source code, yes, in essence, the constructor class of the ForkJoinPool class is called to create a thread pool, and from the perspective of the code structure, the ForkJoinPool class inherits from the AbstractExecutorService abstract class. Next, let's look at the constructor of the ForkJoinPool class.

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

By looking at the source code, we know that the constructor of ForkJoinPool finally calls the following private constructor.

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

The meaning of each parameter is as follows.

  • parallelism: Concurrency level.
  • factory: The factory class object that creates the thread.
  • 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)
复制代码

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

Guess you like

Origin juejin.im/post/7101855019565056031