Executor thread pool for concurrent programming

1. Introduction to Thread Pool

1.1 Thread pool:
"Thread pool", as the name implies, is a thread cache. Thread is a scarce resource. If created without restriction, it will not only consume system resources, but also reduce the stability of the system. Therefore, Java provides a thread pool for threads. Unified allocation, tuning and monitoring;
1.2 Introduction to thread pools
In web development, the server needs to accept and process requests, so a thread is allocated for processing a request. If a new thread is created for each request, it is very easy to implement, but there is a problem: if the number of concurrent requests is very large, but the execution time of each thread is very short, then threads will be created and destroyed frequently. Will greatly reduce the efficiency of the system. It may appear that the server spends more time and system resources on creating new threads and destroying threads for each request than processing actual user requests. So is there a way to execute a task without being destroyed, but can continue to perform other tasks? This is the purpose of the thread pool. The thread pool provides a solution to the problem of thread life cycle overhead and resource shortage. By reusing threads for multiple tasks, the overhead of thread creation is amortized over multiple tasks.
1.3 When to use thread pool?

  • Single task processing time is relatively short
  • The number of tasks that need to be processed is large
    1.4 Advantages of Thread Pool
  • Reuse existing threads, reduce the overhead of thread creation and death, and improve performance
  • Improve response speed. When the task arrives, the task can be executed immediately without waiting until the thread is created.
  • Improve the manageability of threads. Threads are scarce resources. If they are created unlimitedly, they will not only consume system resources, but also reduce the stability of the system. The thread pool can be used for uniform allocation, tuning and monitoring.

2.Executor framework

Executor class diagram
The Executor interface is the most basic part of the thread pool framework. It defines an execute method for executing Runnable.
ExecutorService is a general sub-interface; important methods are defined:

public interface ExecutorService extends Executor {
    
    

    //在完成已提交的任务后封闭办事,不再接管新任务
    void shutdown();

    //停止所有正在履行的任务并封闭办事
    List<Runnable> shutdownNow();

	//测试是否该ExecutorService已被关闭
    boolean isShutdown();
	//测试是否所有任务都履行完毕了
    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

	//可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2.1 There are 5 states of thread pool

RUNNING    = ­1 << COUNT_BITS; //高3位为111
SHUTDOWN   =  0 << COUNT_BITS; //高3位为000
STOP       =  1 << COUNT_BITS; //高3位为001
TIDYING    =  2 << COUNT_BITS; //高3位为010
TERMINATED =  3 << COUNT_BITS; //高3位为011

1、RUNNING

  1. State description: When the thread pool is in the RUNNING state, it can receive new tasks and process the added tasks.
  2. State switching: The initialization state of the thread pool is RUNNING. In other words, once the thread pool is created, it is in the RUNNING state, and the number of tasks in the thread pool is 0!
    2. SHUTDOWN
  3. State description: When the thread pool is in the SHUTDOWN state, it does not receive new tasks, but can process the added tasks.
  4. State switching: When the shutdown() interface of the thread pool is called, the thread pool is changed from RUNNING -> SHUTDOWN.
    3. STOP
  5. State description: When the thread pool is in the STOP state, it does not receive new tasks, does not process the added tasks, and interrupts the tasks being processed.
  6. State switching: When the shutdownNow() interface of the thread pool is called, the thread pool is changed from (RUNNING or SHUTDOWN) -> STOP.
    4. TIDYING
  7. Status description: When all tasks have been terminated and the "number of tasks" recorded by ctl is 0, the thread pool will become TIDYING. When the thread pool becomes TIDYING, the hook function terminated() will be executed. terminated() is empty in the ThreadPoolExecutor class. If the user wants to perform the corresponding processing when the thread pool becomes TIDYING; it can be achieved by overloading the terminated() function.
  8. State switching: When the thread pool is in the SHUTDOWN state, the blocking queue is empty and the tasks executed in the thread pool are also empty, it will be SHUTDOWN -> TIDYING. When the thread pool is in the STOP state, when the tasks executed in the thread pool are empty, it will be STOP -> TIDYING.
    5. TERMINATED
  9. State description: The thread pool is completely terminated, and it becomes the TERMINATED state.
  10. State switching: When the thread pool is in the TIDYING state, after the execution of terminated(), it will be TIDYING -> TERMINATED.
    The conditions for entering TERMINATED are as follows:
  • The thread pool is not in the RUNNING state;
  • The thread pool state is not TIDYING state or TERMINATED state;
  • If the thread pool status is SHUTDOWN and workerQueue is empty;
  • workerCount is 0;
  • Successfully set TIDYING status.

3. Thread pool creation:

byExecutorsIntroduction to the types of thread pools created by API:
3.1 A fixed number of thread pools

    /**
    *创建重复使用固定数量线程的线程池
	*使用提供的
	*在需要时创建新线程的ThreadFactory。在任何时候,
	*最多{@code nThreads}线程将处于活动处理状态
	*任务。如果在所有线程
	*活动,它们将在队列中等待线程
	*可用。如果任何线程在
	*在关闭之前执行,如果
	*需要执行后续任务。池中的线程将
	*存在,直到显式{@ Link ExcutoService }shutdown
    * shutdown}.
	*@param nThreads 线程池中的线程数
	*@param threadFactory创建新线程时要使用的工厂
	*@return 返回新创建的线程池
	*@threadFactory为空时抛出NullPointerException
	*如果{@code nThreads<=0},则@throws IllegalArgumentException
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

3.2. Parallel thread pool
This is the thread pool newly added in 1.8, you can see that ForkJoin related operations are mainly used

    /**
     * 并行线程池
     * 作为其目标并行级别。
	 *@返回新创建的线程池
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
    
    
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

3. Thread pool with only one thread
In fact, this can not be called thread pool, because there is only one thread. Core thread=Maximum thread=1, this is more suitable for scenarios that need to ensure the sequential execution of tasks in the queue.

    /**
	*创建使用单个工作线程操作的执行器
	*从无限的队列中。(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newFixedThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

4. Cache thread pool
He creates threads as needed. There is no core thread. When there are no tasks in 60s, the surviving threads will be recycled. When there are tasks in 60s, he can reuse the existing threads. Note that his work queue is SynchronousQueue, here is a brief introduction), each of his put operations must wait for the take operation, which means that if the task production speed is greater than the consumption speed, then he will not create a new thread. This thread pool is suitable for scenarios where a large number of small tasks are performed.

    /**
	*创建根据需要创建新线程的线程池,但是
	*将重用以前构造的线程
	*可用。这些池通常会提高性能
	*执行许多短期异步任务的程序。
	*对{@code execute}的调用将重用先前构造的
	*线程(如果可用)。如果没有现有线程可用,则新建
	*将创建线程并将其添加到池中。具有
	*60秒未使用被终止并从
	*缓存。因此,一个空闲时间足够长的池将
	*不消耗任何资源。请注意,与
	*属性,但有不同的详细信息(例如,超时参数)
	*可以使用{@link ThreadPoolExecutor}构造函数创建。
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

5. Delayed thread pool
ScheduledThreadPoolExecutor inherits ThreadPoolExecutor, so super will eventually be transferred to the constructor of ThreadPoolExecutor. You can see that the maximum number of threads is the maximum value of int, and the work queue is DelayedWorkQueue. The thread pool is suitable for executing delayed tasks.

    /**
	*创建可以调度命令的单线程执行器
	*在给定的延迟后运行,或周期性地执行。
	*(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newScheduledThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
	*@返回新创建的计划执行器
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
        public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

Guess you like

Origin blog.csdn.net/qq_38130094/article/details/104165504