This paper mainly introduces:

  1. What is a thread pool?
  2. How do I understand the thread pool constructor
  3. What’s wrong with using Executors to create a thread pool?
  4. Properly create thread pool posture

In the Alibaba Java development manual, there is amandatory* Do not use Executors to create thread pools. * Do not use Executors to create thread pools. With that in mind, today we’ll take a look at how Java thread pools work


First up, what is a thread pool? From the definition of Thread Pool, Thread Pool ** is a Thread management tool based on pooling idea. Too many threads will bring extra overhead, such as creating or destroying threads, Thread scheduling, etc. Thread pools avoid this overhead by maintaining multiple threads and, to a certain extent, prevent thread inflation. In terms of usage, thread pool implements thread reuse. Each task submitted will be assigned to a thread to execute, and the thread will be returned to the thread pool after the task is executed

How do I understand the thread pool constructor? We can look at the arguments to create a thread pool with the New TheadPoolExecutor method

public ThreadPoolExecutor(intCorePoolSize, // Number of core threadsintMaximumPoolSize, // Maximum number of threadslongKeepAliveTime, // Keep Alive TimeUnit unit, // BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)       // Reject the policy
Copy the code

Pictures fromImplementation Principle of Java Thread Pool and Its Practice in Meituan Business, I strongly recommend you read the original text.

Here we first give the thread pool to perform the task steps, you can combine with the above diagram, compare. Thread pool design conforms to production consumption model

  1. Threads are not created immediately after the thread pool is initialized, but after the first task is submitted
  2. If the number of threads created is greater than CorePoolSize, the task is put into the work queue for temporary storage
  3. When the work queue is full, create threads to maximumPoolSize threads
  4. RejectedExecutionHandler (RejectedExecutionHandler) If the number of threads has been created to maximumPoolSize and no idle threads are consuming any task, the newly submitted task will be rejected according to the RejectedExecutionHandler
  5. If the number of current threads is greater than the number of core threads and no task is submitted after waiting for KeepAliveTime, the thread is considered idle and the thread pool shrinks to corePoolSize

If you have time, take a look at the source code of the thread pool and see how it is implemented at the code level

All the rejection policies implemented RejectedExecutionHandler AbortPolicy: this interface directly thrown RejectedExecutionException CallerRunsPolicy: DiscardOldestPolicy: Discards the task with the longest waiting time in the work queue and then forwards the task to the work queue. DiscardPolicy: Does not do anything to directly discard the task


So back to the question itself, what’s wrong with using Executors to create a thread pool? CacheThreadPool/ScheduledThreadPool is an unbounded number of threads that can be created by a FixedThreadPool/SingleThreadPool Creating too many threads causes the OOM or CPULoad to spike

Usually, we might be lucky to think that this situation will not happen, but in high concurrency scenarios, this situation is very easy to occur, for example, we rely on the downstream service, QPS is 100, assume that our client timeout is 1 minute, due to network jitter, the downstream service is unavailable for 1 minute. At this point our requests will be hung and 6000 requests will be generated in 1 minute. With a CacheThreadPool asynchronous call, we will create 6000 threads in 1 minute, easily making the service OOM


Create a thread pool using guava ThreadFactory. Create a thread pool using Guava ThreadFactory

@Slf4j
class Solution {
    private static final int CORE_POOL_SIZE = 10;
    private static final int MAX_POOL_SIZE = 150;
    private static final int BLOCKING_QUEUE_SIZE = 10;
    private static final long KEEP_ALIVE_TIME = 10L;

    private static final ThreadFactory guavaThreadFactory =
            new ThreadFactoryBuilder().setNameFormat("thread-pool-%d").build();
    
    private static final ExecutorService exec = new ThreadPoolExecutor(CORE_POOL_SIZE,
            MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(BLOCKING_QUEUE_SIZE), guavaThreadFactory);


    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            exec.submit(() -> log.info("is working")); }}}Copy the code

Guava is a Java development tool provided by Google. The POM coordinates are as follows:

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
Copy the code

When creating a thread pool, you need to separate core functions from non-core functions and set different parameters to avoid mutual influence