preface

Coding with a single thread in mind during daily development, without regard for performance in a multithreaded state. The result is too many requests for the application to respond to. In order to solve the problem of too many requests, the concept of thread pool was derived. Through the “pool” idea, thus reasonable processing requests. This article has documented the use of thread pools in Java and how they work. You are welcome to correct any errors.

What is a thread pool?

Thread pool is a software design pattern for concurrent execution of computer programs. The thread pool maintains multiple threads waiting for tasks to be assigned by the scheduler to execute concurrently, which improves performance and avoids execution delays caused by the frequent creation and destruction of threads for short-term tasks.

What problem does the thread pool solve?

When we talk about thread pool, we must start with the life cycle of the thread.

](/img/bVcSinY)

As you can see from the diagram, no matter how long the task is executed, each thread goes through a state from birth to death. The purpose of using a thread pool is to avoid duplicate creation of the thread and thus save time Running to the Terminated thread. At the same time, the thread will be reused to minimize the savings of system resources and improve the response speed at the same time.

Use of thread pools

Thread pool creation

Use ThreadPoolExecutor with 7 parameters to complete the creation of the thread pool

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • CorePoolSize: The maximum value of the core thread in the thread pool
  • MaximumPoolSize: The maximum number of threads in the thread pool
  • KeepAliveTime: The amount of time that a non-core thread lives when it is idle
  • Unit: KeepAliveTime A unit used in seconds, minutes, hours, etc
  • WorkQueue: The blocking queue type
  • ThreadFactory: A threadFactory used to configure the name of the thread, whether it is a daemon thread, etc
  • Handler: The rejection policy for the thread pool

Common blocking queue

ArrayBlockingQueue

Bounded blocking queue of the underlying array-based implementation

LinkedBlockingQueue

The underlying blocking queue is based on a single linked list. The capacity can be configured. The default capacity without configuration is Integer.MAX_VALUE

Thread factory

inAlibaba Java Development ManualIs mandatory to specify the name of the thread

](/img/bVcSinX)

Since hutool is used a lot for work, it also includes a wrapper around ThreadFactory, which can be conveniently named

ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNamePrefix("myThread-").build();

Rejection policies

When the number of worker threads in the thread pool is greater than MaximumPoolSize, the thread will no longer accept the task and execute the corresponding rejection policy. There are currently four supported rejection policies:

  1. AbortPolicy (default) : Discards the task and throws itRejectedExecutionExceptionabnormal
  2. CallerRunsPolicy: Handled by the caller
  3. Discarded top task in queue and re-queued
  4. DiscardPolicy: Discards the task without throwing an exception

The execution logic of the thread pool

/ / create a thread factory ThreadFactory ThreadFactory = ThreadFactoryBuilder. The create () setNamePrefix (" myThread - "). The build (); ThreadPoolExecutor = new threadPoolExecutor (5, 10, 10, TimeUnit.seconds); new ArrayBlockingQueue<>(100), threadFactory, new ThreadPoolExecutor.AbortPolicy());

The execute () method

// Combine value; Private Final AtomicInteger CTL = new AtomicInteger(CTLOF (RUNNING, 0));
Public void execute(Runnable command) {if (command == null) throw new NullPointerException(); Int c = ctl.get(); If (workerCountOf(c) < corePoolSize) {if (addWorker(command, true)) return; c = ctl.get(); } // If (IsRunning (c) && WorkQueue. Offer (command)) {// Recheck thread pool status int recheck = ctl.get(); // If the thread pool is not Running, remove the added task and execute the rejection policy if (! isRunning(recheck) && remove(command)) reject(command); Else if (WorkerCountOf (reCheck) == 0) addWorker(null, false); } // Failed to add task, reject policy else if (! addWorker(command, false)) reject(command); } // addWorker() completes the creation of the thread

Execute the process

Common thread pool

newCachedThreadPool

Public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.max_value, 60L); TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } // 6 parameters, Public static ExecutorService newCachedThreadPool(ThreadFactory ThreadFactory) {return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }

The maximum number of threads allowed to be created is INTEGER.MAX_VALUE, which may create a large number of requests, resulting in OOM

newFixedThreadPool

// The number of core threads is equal to the maximum number of threads, Public static ExecutorService newFixedThreadPool(int nThreads) {return new using a linked list-based blocking queue with no capacity configured ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); Public static ExecutorService newFixedThreadPool(int nThreads, int nThreads) ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }

The maximum allowable length of the request queue is INTEGER.MAX_VALUE, which may pile up so many requests that an OOM may result

newSingleThreadExecutor

// The core thread and the maximum number of threads are both 1, Use a blocking queue based on linked list public static ExecutorService newSingleThreadExecutor () {return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }

Thread pool with only one thread, receiving tasks is equivalent to serial execution

newScheduledThreadPool

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

A pool of threads that can execute periodically

References:

  1. Java thread pool parsing (juejin.cn)
  2. Stop saying you don’t understand thread pools — be an elegant Siege Lion (juejin.cn)
  3. Java Thread Pool Implementation Principles and Practice in Meituan Business – Meituan Technical Team (meituan.com)

Read the original