ThreadPoolExecutor (ThreadPoolExecutor) is one of the most common classes in Java, and it’s one of the most common classes in Java. It’s one of the most common classes in Java, and it’s one of the most common classes in Java.

I believe you must have thought about a question, in the face of a variety of scenarios, thread pool parameters should be how to design? This must be a super difficult question to answer. A few days ago, I could not think of a standard answer. Fortunately, I found an article published by Meituan in 2020, which gave a very advanced operation — let the parameters of the thread pool be dynamic, which greatly improved the adaptive ability of the system.

Tech.meituan.com/2020/04/02/…

As for why I see =_= now, maybe it’s because I’m too lazy… Let’s first review the core idea of thread pooling, and introduce how to make parameters dynamic in this technique

Quick review of thread pools

The benefits of using thread pools are outlined in The Art of Concurrent Programming in Java as follows:

  • Reduce resource consumption. Reduce thread creation and destruction wastage by reusing created threads.
  • Improve response speed. When a task arrives, it can be executed immediately without waiting for the thread to be created.
  • Improve thread manageability. Thread pools allow for uniform allocation, tuning, and monitoring.

ThreadPoolExecutor: ThreadPoolExecutor: ThreadPoolExecutor: ThreadPoolExecutor: ThreadPoolExecutor

/** * Creates a new ThreadPoolExecutor with the given initial parameters. */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,// the maximum number of threads in the thread pool long BlockingQueue<Runnable> workQueue, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler// RejectedExecutionHandler handler// RejectedExecutionHandler handler// RejectedExecutionHandler We can customize the strategies to deal with the tasks) {if (corePoolSize < 0 | | maximumPoolSize < = 0 | | maximumPoolSize < corePoolSize | | keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }Copy the code

The most important parameters in ThreadPoolExecutor:

  • CorePoolSize: number of core threads. Minimum number of threads that can run simultaneously.
  • MaximumPoolSize: Specifies the maximum number of threads that can run concurrently when the number of tasks in the queue reaches the queue capacity.
  • WorkQueue: When a new task arrives, the system determines whether the number of threads currently running reaches corePoolSize. If so, the new task is queued. If the workQueue is full, the reject policy is executed.

Other parameters of ThreadPoolExecutor:

  • KeepAliveTime: When the number of threads in the thread pool is greater than corePoolSize, threads outside the core thread will not be destroyed immediately, but will wait until the keepAliveTime is exceeded.
  • Unit: keepAliveTime Time unit.
  • ThreadFactory: Used when executor creates a new thread.
  • Handler: rejects the policy.

What exactly does a thread pool work when the parameters are set? Here’s an interview question to help you understand:

Suppose we set the thread pool parameters to corePoolSize=10, maximumPoolSize=20, and queueSize =10

20 concurrent tasks coming in, how many active threads?

10. CorePoolSize is full and queueSize is full

21 concurrent tasks coming in, how many active threads?

11. QueueSize = 20, corePoolSize + 1 = 11

30 concurrent tasks coming in, how many active threads?

20. CorePoolSize is full, queueSize is full, corePoolSize is expanded to 20, and there are 20 active tasks.

31 concurrent tasks coming in, how many active threads?

20. CorePoolSize is full, queueSize is full, corePoolSize is expanded to 20 or more, and there are 20 active tasks if the discard policy is used.

The above process can be summarized as follows:

2 Existing methods of setting parameters and their deficiencies

After reviewing the core technical points of thread pools, it’s time to start thinking about the main topic of this article: How should thread pool parameters be set?

If you type this question into a browser, you’re most likely going to get something like:

The above theory looks gorgeous, but the reality is very cruel… You will find that although the configuration is carried out according to the above guidelines, the result is not satisfactory. There are many reasons for this consequence, including but not limited to:

  • It is not obvious whether the task is CPU-intensive or IO intensive
  • More than one service may be deployed on the same machine, and resources may be preempted between different services

Meituan’s solution to the above problem is to make thread pool parameters dynamic

So how do you make parameters dynamic?

For those of you who are familiar with microservice development, you may think that we can use a configuration center to do this, so that the thread pool parameters can be dynamically configured and immediately effective (there is also a special middleware in Ali, Diamond), without redeploying the program and releasing it. Usually in an enterprise this process is time-consuming.

3 How to Set the number of core threads (corePoolSize)

The ThreadPoolExecutor library has this method directly:

public void setCorePoolSize(int corePoolSize) { if (corePoolSize < 0) throw new IllegalArgumentException(); int delta = corePoolSize - this.corePoolSize; this.corePoolSize = corePoolSize; if (workerCountOf(ctl.get()) > corePoolSize) interruptIdleWorkers(); else if (delta > 0) { // We don't really know how many new threads are "needed". // As a heuristic, prestart enough new workers (up to new // core size) to handle the current number of tasks in // queue, but stop if queue becomes empty while doing so. int k = Math.min(delta, workQueue.size()); while (k-- > 0 && addWorker(null, true)) { if (workQueue.isEmpty()) break; }}}Copy the code

We read the English notes directly, this is what the author is directly trying to express. Roughly translated:

Set the core number of threads. If the new corePoolSize value is smaller than the current corePoolSize value, the additional threads will be terminated the next time they are idle. If the new corePoolSize value is greater than the current corePoolSize value, a new worker can be created to perform tasks in the queue

4 Setting the maximum number of threads (maxPoolSize)

The ThreadPoolExecutor library also has this method:

public void setMaximumPoolSize(int maximumPoolSize) {
    if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
        throw new IllegalArgumentException();
    this.maximumPoolSize = maximumPoolSize;
    if (workerCountOf(ctl.get()) > maximumPoolSize)
        interruptIdleWorkers();
}
Copy the code

This method has a similar comment to the above method, you can look at it:

The logic is not complicated:

  1. Parameter calibration

  2. Set the maximum number of threads maxPoolSize

  3. If the number of working threads is greater than the maximum number of threads, an interrupt is initiated for idle threads

JDK native thread pool ThreadPoolExecutor also provides additional methods for setting parameters:

5 How do I change the length of a waiting queue

Capacity, the length of the wait queue, is modified by the final modifier, so it should not be modified

private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
Copy the code

The only possible way is to define a queue, in the implementation of Meituan is called a ResizableCapacityLinkedBlockIngQueue queue, according to the name isn’t hard to see, the volume of this queue is variable.

The implementation details are not yet available, but we can simply remove the capacity final modifier from the original LinkedBlockingQueue and provide getters and setters. Form our own ResizableCapacityLinkedBlockIngQueue

Recommend more courses:

Java Basics: Java300 set course -Java essential quality tutorial _ Hand by hand graphic learning Java, make learning to be a pleasure _

Python Basics: Getting started with Python! Crash Course Python for beginners! Two months can be the kind of post!

Java Game Project: [Java Project] Develop a full set of king of Glory tutorials and materials, make King of Glory in Java in less than 2 hours

Front End Foundation: Super dry! A week to build a Xiaomi mall! Web front-end zero basic entry HTML5+ CSS3, learn to build a website to see this is enough!