ThreadPoolExecutor thread pool related

Table of contents

Why is there a thread pool?

thread pool status

 ThreadPoolExecutor core parameters

corePoolSize

the case

maximumPoolSize

 the case

keepAliveTime

unit

workQueue

 the case

 threadFactory

the case

handler

the case

 How to close the thread pool

Why is it not recommended to use Executors to create thread pools


Why is there a thread pool?

In actual use, the time spent by the server on creating and destroying threads and the consumption of system resources are quite large, so the number of times to create and destroy threads should be reduced as much as possible.
Since there is no consumption of thread creation and destruction, the system response speed can be improved and
threads can be managed reasonably

thread pool status

1、RUNNING

Status Description: When the thread pool is in the RUNNING state, it can receive new tasks and process added tasks.
2. SHUTDOWN

Status Description: When the thread pool is in the SHUTDOWN state, it does not receive new tasks, but can process added tasks
3, STOP

Status Description: When the thread pool is in the STOP state, it does not receive new tasks, does not process added tasks, and interrupts the tasks being processed.
4. TIDYING

Status description: When all tasks are terminated and the number of tasks recorded by ctl is 0, the state of the thread pool will change to TIDYING state; when the state of the thread pool changes to TIDYING state, the hook function terminated() will be called. The ThreadPoolExecutor is empty. If the user wants to perform corresponding processing when the thread pool becomes TIDYING, the terminated() function needs to be overloaded.
When the thread pool is STOP, when the tasks executed in the thread pool are empty, it will STOP->TIDYING
5, TERMINATED

Status Description: When the thread pool is completely terminated, it will become TERMINATED

 ThreadPoolExecutor core parameters

corePoolSize

corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set

The number of threads held in the pool, even if they are idle, unless allowCoreThreadTimeOut is set

The number of core threads in the thread pool. When a task is submitted, the thread pool creates a new thread to execute the task until the current number of threads is equal to corePoolSize. Even if there are other idle threads that can execute new tasks, threads will continue to be created; 

If the prestartAllCoreThreads() method of the thread pool is executed, the thread pool will create and start all core threads in advance.

the case

The number of core threads and the maximum number of threads are 1, using a blocking queue that does not store elements.

public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0,
                TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < 2; i++) {
            executor.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
            Thread.sleep(1000);
        }
    }

output 

pool-1-thread-1
pool-1-thread-1

maximumPoolSize

maximumPoolSize – the maximum number of threads to allow in the pool

The maximum number of threads allowed to exist in the pool

 the case

The number of core threads is 1, the maximum number of threads is 3, and a blocking queue that does not store elements is used . (Pay attention to eating in combination with workQueue parameters~ )

public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0,
                TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < 3; i++) {
            executor.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }
    }

output

pool-1-thread-1
pool-1-thread-3
pool-1-thread-2 

keepAliveTime

keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating. 

When the number of threads is greater than cores, this is the maximum time that excess idle threads will wait for new tasks before terminating.

The survival time when the thread is idle, that is, when the thread has no tasks to execute, the thread continues to survive; by default, this parameter is only useful when the number of threads is greater than corePoolSize, and idle threads exceeding this time will be terminated;

unit

unit – the time unit for the keepAliveTime argument

Units of the keepAliveTime parameter

workQueue

workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method. 

Used to place unexecuted tasks, this queue will only save runnable tasks submitted by the execute method.

A blocking queue used to hold tasks waiting to be executed.

If the current number of threads is corePoolSize, the tasks that continue to be submitted are saved in the blocking queue and wait to be executed;

If the current blocking queue is full and the task continues to be submitted, a new thread will be created to execute the task, provided that the current number of threads is less than the maximumPoolSize; when the blocking queue is an unbounded queue, the maximumPoolSize will not work because it cannot be submitted to the core thread pool Threads will be continuously put into workQueue.

The JDK provides the following queues:

ArrayBlockingQueue: A bounded blocking queue based on an array structure, sorting tasks by FIFO; (commonly used)

LinkedBlockingQueue: Blocking queue based on linked list structure, sorting tasks by FIFO, the throughput is usually higher than ArrayBlockingQueue; (commonly used)

SynchronousQueue: A blocking queue that does not store elements, each insertion operation must wait until another thread calls the removal operation, otherwise the insertion operation is always blocked, and the throughput is usually higher than LinkedBlockingQueue; (commonly used)

PriorityBlockingQueue: Unbounded blocking queue with priority;

DelayQueue: An unbounded blocking queue implemented using a priority queue.

LinkedTransferQueue: An unbounded blocking queue composed of a linked list structure.

LinkedBlockingDeque: A bidirectional blocking queue composed of a linked list structure.

 the case

The number of core threads is 1, the maximum number of threads is 3, and a queue with a capacity of 1 is used .

public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < 3; i++) {
            executor.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }
    }

 output

pool-1-thread-2
pool-1-thread-1
pool-1-thread-2

 threadFactory

threadFactory – the factory to use when the executor creates a new thread

Create a factory for executors to create threads

Through the custom thread factory, a recognizable thread name can be set for each newly created thread. Defaults to DefaultThreadFactory.

the case

Give the thread a name. I use classes in spring. If you don't want to introduce too many dependencies, you can write a class to change the namePrefix by imitating the code of Executors.defaultThreadFactory().

public static void main(String[] args){
        CustomizableThreadFactory customizableThreadFactory = new CustomizableThreadFactory("mine-");//import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0,
                TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                customizableThreadFactory,
                new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 1; i++) {
            executor.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }
    }

 output

mine-1

handler

handler – the handler to use when execution is blocked because the thread bounds and queue capacities are reached

Handler to use when thread boundaries and queue capacity are reached to block execution

The saturation strategy of the thread pool. When the blocking queue is full and there are no idle worker threads, if you continue to submit tasks, you must adopt a strategy to process the task. The thread pool provides 4 strategies:

AbortPolicy: Throw an exception directly, the default strategy;

CallerRunsPolicy: Use the thread where the caller is located to execute the task;

DiscardOldestPolicy: Discard the top task in the blocking queue and execute the current task;

DiscardPolicy: discard the task directly;

the case

by CallerRunsPolicy为案例。核心和最大线程数为1。

public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0,
                TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i < 3; i++) {
            executor.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }
    }

output

main
main
pool-1-thread-1 

 How to close the thread pool

shutdown:

  1. Modify the thread pool status toSHUTDOWN
  2. No longer accepting new submissions
  3. Interrupt idle threads in the thread pool
  4. Step 3 only interrupts the idle thread, but the tasks being executed and the tasks in the thread pool task queue will continue to be executed

shutdownNow:

  1. Modify the thread pool status toSTOP
  2. No longer accepting task submissions
  3. Attempt to interrupt all threads in the thread pool (including executing threads)
  4. Returns a list of tasks that are waiting to be executed List<Runnable>

Why is it not recommended to use Executors to create thread pools

  • newFixedThreadPool and newSingleThreadExecutor: The blocking queue is an unbounded queue. The main problem is that the accumulated request processing queue may consume a very large amount of memory, or even OOM.
  • newCachedThreadPool and newScheduledThreadPool: The maximum number of threads is Integer.MAX_VALUE, which may create a very large number of threads, or even OOM.

 To be continued... If you think about it, analyze the source code

Guess you like

Origin blog.csdn.net/wai_58934/article/details/126712972