[Learn JAVA from scratch | Article 40] Understand the thread pool

Table of contents

Foreword:

Thread Pool:

The workflow of the thread pool:

The code implements the thread pool:

Task rejection policy: 

How big is the thread pool?

Summarize:


Foreword:

        In Java programming, the thread pool is a powerful tool that can manage and reuse threads and provide efficient concurrent processing capabilities. Through the thread pool, we can effectively control the number of concurrent threads and reduce the overhead of thread creation and destruction. This article will guide you to understand the thread pool in Java, explore its principles, usage and advantages, and provide you with a more efficient programming method.

 

 The role of the thread pool is to manage the number of threads and reduce the frequent creation and destruction of threads

Thread Pool:

        Thread pool is a technology for managing and multiplexing threads, which can effectively handle concurrent tasks and improve program performance and responsiveness. The thread pool maintains a thread queue, which contains a certain number of threads. When a new task arrives, the thread pool will select an idle thread from the queue to execute the task instead of creating a new thread for each task. 

The workflow of the thread pool:

  1. Create a thread pool, including initializing the thread queue and creating a specified number of threads.

  2. Submit tasks to the thread pool. New tasks can be added by submitting task objects to the thread pool.

  3. The thread pool selects an idle thread from the task queue to execute the task.

  4. perform tasks. The threads in the thread pool will perform the operations defined in the task object.

  5. After the task execution is completed, the thread returns to the thread pool and waits for the next task.

  6. The thread pool continues to select new tasks from the task queue and assign them to idle threads, and execute the above steps in a loop.

The code implements the thread pool:

1. Create a thread pool tool class    ExecutorService :

  • public static ExecutorService newCachedThreadPool() Creates an unlimited thread pool
  • public static ExecutorService newCachedThreadPool(int int nthread) creates a capped thread pool

In fact, the first created thread pool is not really without an upper limit, its upper limit is the maximum range of int , but because it is too big, so we say there is no upper limit.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小为5的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        // 提交任务给线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            threadPool.execute(new Runnable() {
                public void run() {
                    try {
                        System.out.println("开始执行任务:" + taskId);
                        Thread.sleep(2000); // 模拟任务执行时间
                        System.out.println("任务执行完成:" + taskId);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // 关闭线程池
        threadPool.shutdown();
    }
}

 Tips:

By means of breakpoints, we can see the number of threads in the current thread pool in real time:

2. Customize the thread pool object  ThreadPoolExecutor :

In Java, we can use ThreadPoolExecutor to customize the creation of thread pool objects. ThreadPoolExecutor is an implementation class of the ExecutorService interface, which allows us to flexibly configure the number of core threads, maximum number of threads, thread survival time and other parameters of the thread pool.
First, we need to import the java.util.concurrent package. Then, a custom thread pool object can be created by the following code:

public class test03 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,//核心线程数量

                6,//最大线程数

                60,//空闲线程最大存活时间

                TimeUnit.SECONDS,//时间单位

                new ArrayBlockingQueue<>(3),//指定任务队列最大长度

                Executors.defaultThreadFactory(),//创建线程工厂

                new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
        );
        
    }
}

In the above code, we pass in parameters such as the number of core threads, the maximum number of threads, the idle timeout of non-core threads, and the task queue to create a thread pool object. You can also adjust these parameters to meet your actual needs.

  1. Number of core threads (corePoolSize) : The number of core threads is the number of threads that are always alive in the thread pool . When submitting a task, if the current number of core threads has not reached the set value, the thread pool will create a new core thread to process the task. Even if core threads are idle, they will not be recycled.

  2. Maximum number of threads (maxPoolSize) : The maximum number of threads is the maximum number of threads that can be accommodated in the thread pool. When the number of submitted tasks exceeds the number of core threads and the task queue is full, the thread pool will create new threads to execute tasks until the maximum number of threads is reached. Tasks that exceed the maximum number of threads will be refused to execute.

  3. Non-core thread idle timeout (keepAliveTime) : When the number of threads in the thread pool exceeds the number of core threads, and these threads are idle, non-core threads will be recycled. The idle timeout sets the maximum survival time of non-core threads, beyond this time, idle non-core threads will be recycled .

Task rejection policy: 

In Java, the task rejection policy is used to handle the behavior of the thread pool when it cannot accept more tasks. When the thread pool is full and the work queue is full or at maximum capacity, newly submitted tasks may be refused execution. Java provides four default task rejection strategies :

  1. AbortPolicy (abort policy) : This is the default task rejection policy. When the thread pool cannot accept new tasks, the newly submitted tasks will immediately throw RejectedExecutionException.

  2. CallerRunsPolicy (Caller Run Policy) : If the thread pool cannot accept new tasks, the task is executed by the thread that submitted the task. This means that the execution of the task will fall back to the calling thread, thereby reducing the overall concurrency.

  3. DiscardPolicy (discard policy) : When the thread pool cannot accept new tasks, newly submitted tasks will be silently discarded without throwing any exceptions. This means that dropped tasks will not be executed.

  4. DiscardOldestPolicy (discard the oldest policy) : When the thread pool cannot accept new tasks, the thread pool will discard the oldest task in the work queue (that is, the task submitted first), and then try to submit a new task again.

In addition to these four default rejection strategies, you can also customize the task rejection strategy by implementing the RejectedExecutionHandler interface. By implementing this interface, you can define your own rejection policy logic, such as recording rejected tasks or putting them in other queues. Then, a custom deny policy can be passed to the thread

In the custom thread pool, we need to grasp the meaning of the seven parameters in the custom process.

How big is the thread pool?

The calculation of the thread pool size has a calculation formula. Before introducing the calculation formula, we must first explain what is the maximum number of parallelism

Maximum parallelism refers to the maximum number of threads or tasks that can be executed simultaneously under a given system environment.

Thread pool size calculation formula: 

1. CPU-intensive computing :
        In CPU-intensive computing, the task is mainly performed by the CPU and involves less I/O operations. In this case, the size of the thread pool can be calculated by the following formula:

最大并行数+1

2. I/O-intensive operations:

        In I/O-intensive computing, tasks involve a large number of I/O operations, such as reading files, network communication, and so on. In this case, since a lot of time in the task execution time is blocked on I/O waiting, the size of the thread pool can be calculated by the following formula:

Nthreads = Ncpu * Ucpu * (1 + (W/C))
  • Nthreads is the number of threads in the thread pool.
  • Ncpu is the number of CPU cores in the computer.
  • Ucpu is the desired CPU utilization (0 <= Ucpu <= 1). It represents the ratio of expected CPU working time to total time.
  • W/C Usually set to a large value so that the CPU can perform other tasks during the I/O wait.

In I/O-intensive tasks, increasing the size of the thread pool can make better use of the I/O waiting time and improve the overall concurrency performance. However, an excessive number of threads will also increase the overhead of context switching, so it needs to be based on the actual

Summarize:

        Today we learned about the use of thread pools, and learned about calling library classes to implement thread pools and custom thread pools. In fact, the content of multi-threading has not been introduced completely. We will introduce the more important optimistic locks and pessimistic locks in threads in detail later, as well as the famous CAS algorithm.

If my content is helpful to you, please like, comment and bookmark . Creation is not easy, everyone's support is my motivation to persevere!

Guess you like

Origin blog.csdn.net/fckbb/article/details/132147602