java thread pool configuration details

Posted by Accurax on Wed, 05 Jan 2022 06:29:37 +0100

java thread pool configuration details

ThreadPoolExecutor full parameter construction

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

Parameter description

corePoolSize -- number of core threads.

For example, if it is set to 5, the thread will not be initialized by default,

When the total number of tasks submitted by the program is less than 6, the thread pool creates threads when the submitted threads are received.

maximumPoolSize -- maximum number of threads. For example, if it is set to 10, a maximum of 10 threads will be created in the thread pool.

keepAliveTime, unit -- the idle time (value and unit) before the thread is recycled when the number of threads is more than the number of core threads.

For example: configure for 30 seconds. According to the examples of 5 and 10 above, when there are more than 5 threads in the thread pool,

If the idle time exceeds 30 seconds, the thread will be recycled.

workQueue -- task queue. When a submitted task needs to be queued for processing, the task will be placed in the queue for processing.

When are you in the queue? When the number of active threads is greater than or equal to the number of core threads, the operation is queued.

When to create threads larger than the number of core threads?

If the queue is full, call the thread creation method. If the creation is successful, the current task starts running in the new thread.

What if the number of threads reaches online? Execute the reject policy.

threadFactory -- thread factory.

Controls the creation of Thread objects in the thread pool. When creating a thread, set the thread name and whether it is a background thread.

handler -- reject policy. When a task cannot be added to the thread for execution or to the task queue, it is handled according to this policy

By default, the interrupt strategy is adopted and exceptions are thrown.

That is, the RejectedExecutionException exception is thrown when the submitted task needs to be rejected.

Parameter action interpretation

After creating a thread pool, when submitting a task, when the number of threads held in the thread pool is less than the core thread, create a thread for each task submitted until the number of threads held is equal to the number of core threads.

When submitting a task again, judge whether there are idle threads. If there are idle threads, execute the task directly. If there are no idle threads (the number of active threads is equal to the number of core threads), execute the queue operation to add the task to the task queue.

When adding a task queue, if the queue is not full, write to the queue and wait for execution. If the queue is full, the new thread process is executed.

When creating a new thread, first judge whether the current number of threads reaches the maximum number of threads. If not, create a new thread and execute the task submitted by this operation in the thread. The tasks in the original queue continue to queue. If the number of threads has reached the maximum number of threads, the reject policy is executed.

When the number of threads is greater than the number of core threads, the thread recycling process is executed. When the idle time of the thread reaches the configured keep alive time (unit), the idle thread is recycled.  

The work of creating a thread is completed by the thread factory. When creating a thread, set the thread name, whether to background thread and thread priority.

Thread pool usage

// Single thread thread pool, the core thread and maximum thread are 1, and the task queue size is integer MAX_ VALUE
// Used to handle single threaded queued tasks
ExecutorService executor = Executors.newSingleThreadExecutor();

// Fixed number of threads, thread pool, core threads and maximum threads are the specified number of threads, and the size of task queue is integer MAX_ VALUE
// Used to handle multithreaded concurrent processing. You can also specify a thread factory
ExecutorService fixedExecutor = Executors.newFixedThreadPool(5);

// Cache thread pool, the number of core threads is 0, and the maximum number of threads is integer MAX_ Value, idle time is 1 minute
// When submitting a task, if there is an idle thread, the idle thread will be used to execute the task. If there is no idle thread, a thread will be created to execute the task
ExecutorService cachedExecutor = Executors.newCachedThreadPool();

// Plan the task thread pool, execute periodically, and trigger execution at a certain interval
ExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5);

Although the above three thread pools can meet most business scenarios, they do not have the seven parameters necessary for reasonable configuration of thread pools. In actual use, we should select the appropriate thread pool in combination with our own scenarios.

First of all, you need to consider how much concurrency is required for the problem to be solved, how much concurrency is required in the actual scenario, and how much concurrency your own server supports. In general, IO type can have more concurrent threads. After all, IO processes consume network card resources and consume less CPU. CPU intensive tasks generally do not exceed the number of CPU cores.

Then you need to select an appropriate queue size, especially when the task consumption time is unknown and the number of queues is unpredictable, you must formulate an appropriate queue size and set a rejection policy. If the task queue size is not limited, it defaults to integer MAX_ Value, so many Runnable objects may cause memory overflow.

The appropriate reject policy will work when the number of tasks exceeds our expectations. The default reject policy will throw an exception to indicate that there is a problem with the thread pool.

Role of thread pool

Finally, let's briefly talk about the role of thread pool I understand.

        1. Thread pool solves the problem that creating threads consumes resources, mainly by reusing threads to reduce the resource overhead as a whole. See the final test results (thread and task time-consuming test) for details.

        2. It solves the problem of thread management. Thread, as a system resource, is valuable and limited. The program uses thread and has high technical requirements. Otherwise, it may lead to thread resource depletion, memory overflow and high CPU utilization.

        3. It reduces the threshold of thread use and simplifies the use of multithreading. Using thread pool can help us write simple, elegant and efficient programs more efficiently.              

Test content

Thread and task time consuming test - PC test results:

The thread pool uses newCachedThreadPool. The results are as follows:

10000 task submissions and 10 tests10000 thread startup tests 10 times
41ms~48ms304ms~357ms

The test code is as follows:

    // 10000 missions
    private static void testTask(){
        long t1 = System.nanoTime();
        ExecutorService cachedExecutor = Executors.newCachedThreadPool();
        for(int i=0;i<10000;i++){
            cachedExecutor.submit(new Runnable() {
                @Override
                public void run() {
                }
            });
        }
        cachedExecutor.shutdown();
        long t2 = System.nanoTime();
        System.out.println("RunTask:"+(t2-t1));

    }
    //10000 threads
    private static void testThread(){
        long t1 = System.nanoTime();
        for(int i=0;i<10000;i++){
            new Thread().start();
        }
        long t2 = System.nanoTime();

        System.out.println("RunThread:"+(t2-t1));
    }

Topics: Java Multithreading thread pool