preface

What is a thread pool

  • A thread usage pattern. Too many lines will bring scheduling overhead, which will affect cache locality and overall performance. A thread pool maintains multiple threads, waiting to be assigned tasks that can be executed concurrently. This avoids the cost of creating and destroying threads while working on short-duration tasks.
  • Thread pools not only ensure full utilization of CPU cores, but also prevent overscheduling. The number of threads available should depend on the number of concurrent processors available, processor cores, memory, network sockets, and so on. For example, the number of threads is usually the number of cpus +2, because too many threads cause additional thread switching overhead.
  • That is, the number of threads in the thread pool is not better.

The scope of the thread pool

  • A large number of threads are required to complete the task, and the time to complete the task is relatively short. Thread pooling is appropriate for WEB servers to perform tasks such as WEB page requests. Because the individual tasks are small and the number of tasks is huge.
  • But for long tasks, the benefits of thread pools are less obvious. Because a thread cannot be reused after it is created, a large number of tasks block and no thread can execute it.
  • Applications that are performance-critical, such as requiring servers to respond quickly to customer requests.
  • An application that accepts a large number of requests without causing a large number of threads on the server. A large number of sudden customer requests, without a thread pool, will generate a large number of threads. Although the maximum number of threads in most operating systems is theoretically not an issue, creating a large number of threads in a short period of time can cause memory to reach its limit and cause an “out of memory (OOM)” error.

Java thread pool

Thread pools originate from the Executor interface

  • One branch of the Executor interface, as shown below:

Use of thread pools

Code sample

public class ExecutorTest2 {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(8.10.0, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(5), new ThreadPoolExecutor.AbortPolicy());// Create a thread pool
        Runnable runnable = ()-> {// The contents of the runable task
            try {
                //System.out.println(executorService);
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName());

            } catch(Exception e) { e.printStackTrace(); }}; IntStream.range(0.9).forEach(i-> executorService.submit(runnable));// Submit 9 tasks like thread poolexecutorService.shutdown(); }}Copy the code

Creating a thread pool

The Executors class has factory methods that can be used to create thread pools, but they’re not used in real applications.

Constructor of ThreadPoolExecutor

Parameter interpretation

Parameters:

  • CorePoolSize – Number of core threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
  • MaximumPoolSize – The maximum number of threads allowed in the pool
  • KeepAliveTime – When the number of threads is greater than the number of cores, this is the maximum time that extra idle threads can wait for a new task before terminating.
  • Unit – keepAliveTime Time unit of the keepAliveTime parameter
  • WorkQueue – A queue used to save tasks before they are executed. This queue will only hold Runnable tasks submitted by the execute method.
  • ThreadFactory – The factory that the executable uses to create new threads
  • Handler – The handler used when a task cannot be put into a thread pool because thread maximumPoolSize and workQueue capacity have been reached

Throws: IllegalArgumentException

  • If one of the following is true:
    • corePoolSize < 0

      keepAliveTime < 0

      maximumPoolSize <= 0

      maximumPoolSize < corePoolSize

NullPointerException

  • If workQueue or threadFactory or Handler is null

Abstraction about thread pools and the flow of execution

  • abstract

  • process

General execution strategy for thread pools:

  1. If the number of threads executing in the thread pool is < corePoolSize, the thread pool will preferentially create new threads rather than add submitted tasks to the workQueue.
  2. If the number of threads executing in the thread pool >= corePoolSize, the thread pool will preferentially queue the submitted task over creating a new thread.
  3. If the submitted task cannot be added to the blocking queue, the thread pool creates a new thread. If the number of threads created exceeds maximumPoolSize, the rejection policy (handler) takes effect.

It’s time to read the JDK source code again

Rejection policies

  • AbortPolicy

  • DiscardPolicy

  • DiscardOldestPolicy

  • CallerRunsPolicy

The RejectedExecutionHandler interface is not used in JDK RejectedExecutionHandler

The submit method

  • The mechanism of the submit

Summary of thread pool task submission:

  • There are two submission methods: Submit and execute.

  • Submit comes in three ways, each of which ultimately converts the passed task into a Callable object for processing.

  • After a Callable object is constructed, the Execute method declared in the Executor interface is called for unified processing.

Status of the thread pool

There are five states in a thread pool:

  • RUNNING: The thread pool can receive new task submissions and can normally process tasks in the blocking queue.
  • SHUTDOWN: No new task submissions are received, but the thread pool can continue to process tasks in the blocking queue.
  • STOP: stops receiving new tasks and discards existing tasks in the blocking queue. In addition, it interrupts the task in progress.
  • TIDYING: After all tasks are executed (including tasks in the blocking queue) and the number of active threads in the current thread pool drops to zero, the terminated method is called.
  • TERMINATED: the TERMINATED state of the thread pool that will be under TERMINATED when the TERMINATED method is executed.

The thread pool state does not change continuously, it transitions to the appropriate state as the case may be. It doesn’t have to be RUNNING to SHUTDOWN. RUNNING -> SHUPDOWN: when the shutdown method of the thread pool is called, or when the Finalize method is implicitly called (the shutdown method is called internally). RUNNING, SHUTDOWN -> STOP: When the shutdownNow method of the thread pool is called. SHUTDOWN ->TIDYING: When both the thread pool and the blocking queue become empty. STOP ->TIDYING: When the thread pool becomes empty. TIDYING ->TERMINATED: when the TERMINATED method is TERMINATED.

State from JDK source

You can read the JDK to learn how to implement the execute method

How is thread pool state shutdown