Benefits of thread pools

  1. Reduce resource consumption. Reduce the cost of thread creation and destruction by reusing existing threads
  2. Improve response speed. When a task arrives, it can execute immediately without waiting for a thread to be created
  3. Improved thread manageability. Threads are scarce resources. Unified allocation, tuning, and monitoring by thread pools can reduce resource consumption and improve system stability

Seven construction parameters for the thread pool

  1. CorePoolSize (base size of thread pool)

When a task is submitted to the thread pool, the thread pool creates a thread to execute the task, even if other free base threads are able to execute new tasks. 2. MaximumPoolSize Specifies the maximum number of threads allowed to be created by the thread pool. If the queue is full and the number of threads created is less than the maximum number, the thread pool will create a new thread to execute the task. Note that this parameter has no effect if an unbounded blocking queue is used as a task queue. KeepAliveTime Indicates how long a thread pool can remain alive after a worker thread is idle. If there are many tasks and the execution time of each task is short, you can increase the time. Unit Optional units are DAYS, HOURS, MINUTES, MILLISECONDS, MICROSECONDS, and NANOSECONDS. WorkQueue A blocking queue used to hold tasks waiting to be executed. You can select one of the following blocking queues: ArrayBlockingQueue ArrayBlockingQueue ArrayBlockingQueue ArrayBlockingQueue ArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue ArrayArrayBlockingQueue arrayArrayBlockingQueue SynchronousQueue a blocking queue that does not store elements. Each insert must wait until another thread calls a remove operation. Otherwise, the inserts are consistently blocked. Throughput is usually higher than LinkedBlockingQueue – PriorityBlockingQueue an unbounded blocking queue with priority.

ThreadFactory is used to set the factory for creating threads. You can use threadFactory to give each thread a meaningful name. Rejection Policy When both the task and the thread pool are full, the thread pool is saturated and a policy must be adopted to handle new submitted tasks. In JDK5, the thread pool framework provides the following four policies: You can also implement the RejectedExecutionHandler interface to customize the policy

  • AbortPolicy: Directly throws an exception. This policy is adopted by default
  • CallerRunsPolicy: Runs the task using the caller’s thread
  • DiscardOldestPolicy: Discards the last task in the queue and executes the current task
  • DiscardPolicy: Do not process, discard

The thread pool submits the task flow

  1. After the task is submitted, the thread pool determines whether the number of and core procedures is full, and if not, it creates a thread to execute the task.
  2. If the number of core threads is full, then determine whether the task queue is full, if the task queue is not full, then add the task to the task queue
  3. If the task queue is full, determine whether the number of threads in the current thread pool is less than the maximum number of threads, and if so, create a thread to execute the task.
  4. If the number of threads is already equal to the maximum number of threads, the task cannot be processed by the thread pool and the corresponding reject policy is executed.

Thread pool life cycle

  1. Call when the thread pool is running properlyshutdownMethod, the thread pool is inshutdownState, where the thread pool accepts no new tasks and continues to process tasks in the task queue and tasks that the thread is working on.
  2. If the shutdownNow method is called directly, the thread pool will not accept new tasks, and both the currently executing task and the tasks in the task queue will stop executing. The thread pool will then be stopped and return a list of tasks that have not been executed.
  3. The tasks in the thread pool are all stopped and the worker threads are all finished, namely the tinying state.
  4. Terminated state, thread pool destroyed.

How does a thread pool implement thread reuse?

As we all know, a thread would normally need to be reclaimed by the Java virtual machine after executing the run method, so why are threads in the thread pool reused?

Let’s start with the answer, which is actually very simple, which is not to let the run method finish, through the form of an infinite loop and blocking, to reuse the thread.

Thread execution Java task core code is as follows:

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // Keep trying to get the task from the task queue getTask() method, and block the current thread if it doesn't get the task
            while(task ! =null|| (task = getTask()) ! =null) {
                w.lock();
                if((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && ! wt.isInterrupted()) wt.interrupt();try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        // Get the task thread to execute the task's run method
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally{ afterExecute(task, thrown); }}finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally{ processWorkerExit(w, completedAbruptly); }}Copy the code

In the thread pool, each thread is packaged as a Worker object. In a HashSet, the Worker will constantly try to obtain the task from the blocking queue. If the task is successfully obtained, the task will be executed; otherwise, the blocking queue will block the current thread and suspend the current thread. Waiting for a task in the blocking queue to wake up the thread again, (: is this pattern similar to the producer-consumer pattern we studied?

The JDK provides five thread pools

  1. newSingleThreadExecutor
    public static ExecutorService newSingleThreadExecutor(a) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1.1.0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
Copy the code

The core thread count and the maximum thread count are both 1, and the blocking queue is an unbounded LinkedBlockingQueue. This thread pool is suitable for sequential execution of tasks, which has disadvantages but does not take full advantage of CPU multi-core performance. 2. NewFixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
Copy the code

The number of core threads is equal to the maximum number of threads, and the blocking queue is an unbounded LinkedBlockingQueue. This thread pool is suitable for scenarios where you can estimate how many core threads are needed

    public static ExecutorService newCachedThreadPool(a) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
Copy the code

The number of core threads is 0, the maximum number of threads is int, the maximum number of threads is infinite, the thread execution lifetime is 60 seconds, and the blocking queue is SynchronousQueue. This blocking queue has no capacity and its function is equivalent to forwarding tasks. New worker threads will be constantly created when the task in this thread pool comes, so it is suitable for performing a large number of lightweight tasks

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
Copy the code

The blocking queue of the thread pool is a delay queue, which maintains a large root heap for sorting tasks. The thread pool is suitable for executing scheduled or delayed tasks. 5. newWorkStealingPool

    public static ExecutorService newWorkStealingPool(a) {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null.true);
    }
Copy the code

ForkJoin is a new thread pool in JDK1.8 that uses the ForkJoin technology to split tasks, execute them in parallel, and then aggregate the results, similar to the didivide and conquer algorithm.

Thread pool thread count Settings

Method 1 – Speaking from experience

Generally, thread pools can be divided into two types of tasks, one is IO intensive and the other is CPU intensive.

  • IO intensive: Number of CPU cores x 2

Since I/O does not occupy CPU resources, you can open more threads

  • CPU intensive: Number of CPU cores + 1

A production environment, it is difficult to get the setting for the specific number of threads by calculation, because there are many interference factors, see: mp.weixin.qq.com/s/G0toGUjKQ…

Mode 2 – Task quantization

You can accurately calculate the number of core threads, the maximum number of threads, blocking queue size and other information. I didn’t see, the feeling is not the number of CPU cores into consideration, his thought is not quite right, everyone interested can look at www.cnblogs.com/waytobestco…

Appendix & Reference documentation

  • The thread pool principle article www.jianshu.com/p/9a8c81066…
  • The thread pool parameter set blog.csdn.net/u011519624/…
  • Blog.csdn.net/weixin_4477…
  • www.cnblogs.com/waytobestco…