Abstract: From the source code to create a thread pool in-depth analysis of what ways can create a thread pool.

This article is shared from huawei cloud community “[high concurrency] from the source point of view of the creation of thread pool what are the methods”, author: Glacier.

Thread pools have always been a hot topic in the high-concurrency world of Java. So, what are the following ways to create a thread pool: * If you’ve been using the Executors tools? Let’s take a closer look at how you can create a thread pool from the source code.

Create a thread pool by using the Executors tool class

Use the Executors tool to create a thread pool so easy that you don’t need to pay attention to the details of the thread pool. Just pass in the necessary parameters. The Executors tool provides several methods for creating a thread pool, as shown below.

  • Executors. NewCachedThreadPool: create a cacheable thread pool, if thread pool size exceeds the needs, flexible and recycle the idle thread, if there is no recycled thread, new threads

  • Executors. NewFixedThreadPool: create a long thread pool, can control the maximum number of concurrent threads, beyond the thread will be waiting in the queue

  • Executors. NewScheduledThreadPool: create a long thread pool, support time, periodic task execution

  • Executors. NewSingleThreadExecutor: create a single threaded thread pool, using a unique work threads to execute tasks, ensure that all tasks according to the specified sequence (first-in, first-out or priority)

  • Executors. NewSingleThreadScheduledExecutor: create a single threaded thread pool, support time, periodic task execution

  • Executors. NewWorkStealingPool: create a work with parallel level – stealing thread pool

Among them, the Executors. NewWorkStealingPool method is a Java 8 in new way to create a thread pool, it can set parallel levels for the thread pool, has a higher degree of concurrent and performance. Other than this method, the other methods that create thread pools essentially call the constructor of the ThreadPoolExecutor class.

For example, we could create a thread pool using the following code.

Executors.newWorkStealingPool();
Executors.newCachedThreadPool();
Executors.newScheduledThreadPool(3);
Copy the code

Create a thread pool using the ThreadPoolExecutor class

The ThreadPoolExecutor class is AbstractExecutorService derived from an AbstractExecutorService class.

You can also create a thread pool by calling the ThreadPoolExecutor constructor instead of using the Executors class. For example, if the closure-builder uses the Following methods to create a thread pool: Next, let’s 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;
}
Copy the code

As you can see from the source code for the constructor of the ThreadPoolExecutor class, the constructor that is ultimately 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;
}
Copy the code

For more information on what the parameters in this constructor mean and what they do, see “High Concurrency: A ThreadPoolExecutor Class”.

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

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                       60L, TimeUnit.SECONDS,
                       new SynchronousQueue<Runnable>());
Copy the code

Create a thread pool using the ForkJoinPool class

The following methods are added to create a thread pool in the Executors tool class of Java8.

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);
}
Copy the code

In the source code, we can create a thread pool by calling the ForkJoinPool constructor class, which is derived from the AbstractExecutorService abstract class. Next, we 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);
}
Copy the code

By looking at the source code, ForkJoinPool constructors end up calling the following private constructors.

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);
}
Copy the code

The following table describes the meanings of parameters.

  • Parallelism: Concurrency level.

  • Factory: The factory class object that creates the thread.

  • Handler: When a thread in the thread pool throws an uncaught exception, the UncaughtExceptionHandler object is used to handle it.

  • Mode: the value can be FIFO_QUEUE or LIFO_QUEUE.

  • WorkerNamePrefix: Prefix of the name of the thread executing the task.

Of course, the private constructor is one of the methods with the most parameters, but it does not directly external methods, so we can create a thread pool as follows.

new ForkJoinPool();
new ForkJoinPool(Runtime.getRuntime().availableProcessors());
new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
Copy the code

Using ScheduledThreadPoolExecutor class to create a thread pool

The following method classes exist in the Executors tool class to create a thread pool.

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); }Copy the code

From the source, the several methods are essentially call ScheduledThreadPoolExecutor class constructor, ScheduledThreadPoolExecutor that exist in the constructor as shown below.

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);
}
Copy the code

And look from the code structure, ScheduledThreadPoolExecutor class inherits from ThreadPoolExecutor class, or call ThreadPoolExecutor constructor of a class, essentially just transfer queue for DelayedWorkQueue at this time. We can direct call ScheduledThreadPoolExecutor class constructor to create a thread pool, such as in the following form to create a thread pool.

new ScheduledThreadPoolExecutor(3)
Copy the code

Click to follow, the first time to learn about Huawei cloud fresh technology ~