Java -- thread pool (I)

1. Why use thread pools?
For example, we currently have a task that outputs the name of the current thread. Then we create a task, create a thread, give the task to the thread, and then start the thread.

public class Task implements Runnable{
    @Override
    public void run() {
        //Outputs the name of the current thread
        System.out.println(Thread.currentThread().getName());
    }
}
public class ThreadPool001 {
    public static void main(String[] args) {
        //Create task
        Runnable task = new Task();
        //Create thread
        Thread thread = new Thread(task);
        //Start thread
        thread.start();
    }
}
Output results:
"C:\Program Files\Java\jdk1.8.0\bin\java.exe"
Thread-0

Our thread can only execute one task. We can't create multiple tasks and put them on the same thread for continuous execution. We can only re create other threads and start and execute them. The thread will be destroyed after executing the task. If there are more tasks to execute, you need to recreate the thread. The problem is that * * threads cannot be reused. Creating and destroying threads repeatedly will take time and resources. * * at this time, we should consider if threads can be reused. The advantage is to save time and resources. We can see how the thread pool performs tasks.

public class ThreadPool001 {
    public static void main(String[] args) {
        //Create task
        Runnable task1 = new Task();
        Runnable task2 = new Task();
        Runnable task3 = new Task();
        //Create a thread pool with only one thread
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //Submit task
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        //The thread pool will automatically allocate threads to execute the submitted tasks. Finally, you need to call the shutdown method to close the thread pool
        threadPool.shutdown();
    }
}

We create a threadPool with only one thread and submit the created three tasks to the thread pool. The thread pool will automatically allocate threads to execute the submitted tasks. Finally, we need to call the shutdown method to close the thread pool. When the thread pool is closed, no more tasks can be submitted.

Output results:
"C:\Program Files\Java\jdk1.8.0\bin\java.exe" 
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1

From the results, we can see that a thread performs three tasks. At this time, the front thread can be reused. Compared with threads, thread pools have many advantages. Here are three:

  • Reduce resource consumption: reduce the consumption caused by thread creation and destruction by reusing the created threads;
  • Improve response speed: when there is a task, it can be executed immediately without waiting for the thread to be created;
  • Improve thread manageability: thread pools can be uniformly allocated, tuned and monitored.

Threads are scarce resources in our system. Unlimited and repeated creation not only consumes system resources, but also reduces the stability of the system.

2. What is a thread pool?

Thread Pool is a tool to manage threads based on the idea of pooling. The Thread Pool creates threads in advance. When a task needs to be executed, it submits the task to the Thread Pool. The Thread Pool allocates threads to execute. The threads in the Thread Pool can also be reused. After executing a thread, it can then execute other tasks. When all tasks are executed, we can choose to close the Thread Pool or wait for receiving tasks.

UML class diagram of ThreadPool:

3. Why is it recommended to create thread pools natively?

There are eight ways to create a thread pool, but they never change. They are the way to create a thread pool natively. This method is also highly recommended by Ali. The manual explains that thread pools are not allowed to be created by Executors, but by ThreadPoolExecutor. Other methods are at risk of resource consumption.

From the above class diagram, we can see that only ThreadPoolExecutor and ScheduleThreadPoolExecutor can be instantiated. ThreadPoolExecutor is the core class of thread pool. The core class has four construction methods, but they are similar. We can learn from the last construction method with the most parameters.

The first type: most parameters

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

Parameter meaning:
corePoolSize: number of core threads in thread pool int type

maximumPoolSize: the maximum number of threads allowed in the thread pool. Type int

keepAliveTime: the idle time allowed by threads in the thread pool. long type

Unit: the unit of idle time allowed by thread pool maintenance threads

 MICROSECONDS    Microsecond one millionth of a second/1000)
 MILLISECONDS    Millisecond thousandth of a second    
 NANOSECONDS   Nanosecond one billionth of a second/1000)
 SECONDS          second
 MINUTES     minute
 HOURS      hour
 DAYS      day

workQueue: the buffer queue used by the thread pool

handler: the processing policy of the thread pool for rejecting tasks

ThreadPoolExecutor.DiscardPolicy() discards the current task.

threadFactory: thread factory, which is mainly used to create threads: the default value is DefaultThreadFactory


For example:
corePoolSize: 10
maximumPoolSize: 25
keepAliveTime: 10
unit: TimeUnit.SECONDS

The idle thread has a survival time of 10 seconds and will be destroyed if there is no work within 10 seconds. If the idle time is 0 seconds, the idle thread will not be destroyed. There are 10 core threads in the thread pool. If the thread pool is not closed, the 10 core threads will not be destroyed. The maximum number of threads in the thread pool is 25. Threads other than core threads are non core threads, and non core threads are not allowed The execution task will be cleaned up and destroyed. How long it can survive before being cleaned up and destroyed depends on keepAliveTime and unit.

workQueue task queue: the tasks of the thread pool are stored in this container, and the threads in the thread pool also obtain tasks from this container. The commonly used task queues are linked blocklingqueue chain blocking queue based on linked list and ArrayBlocklingQueue array blocking queue based on array.

threadFactory thread factory: This is an interface. You can customize the thread related settings by implementing its internal newThread method. For example, you can specify the thread name to view the thread execution in the later log; you can also specify whether the thread can be a background thread, etc.

handler thread rejection policy: if the following four conditions are met at the same time, the tasks submitted to the thread pool will be rejected.

  • Threads in the thread pool are full
  • Unable to continue capacity expansion
  • There are no idle threads, and all threads are executing tasks
  • The task queue is full and new tasks cannot be saved

Code example:

Task class: outputs the name of the current thread
public class Task implements Runnable{
    @Override
    public void run() {
        //Outputs the name of the current thread
        System.out.println(Thread.currentThread().getName());
    }
}
Thread factory class:
public class CustomThreadFactory implements ThreadFactory {
    //Define a counter and number the thread. The initial number is 1 to avoid thread safety problems
    private final AtomicInteger i = new AtomicInteger(1);
    @Override
    public Thread newThread(Runnable r) {
        //Create a thread and specify a task
        Thread thread = new Thread(r);
        //Set thread name
        thread.setName("Thread:"+i.getAndIncrement()+"number");
        //Return thread
        return thread;
    }
}
public class ThreadPool001 {
    public static void main(String[] args) {
        //Create task
        Runnable task1 = new Task();
        Runnable task2 = new Task();
        Runnable task3 = new Task();
        //Create thread pool
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 25, 10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(),
                new CustomThreadFactory(),  //Thread factory just created
                new AbortPolicy());//Default reject policy
        //Submit task
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        //Close thread pool
        threadPool.shutdown();
    }
}
Output results:
"C:\Program Files\Java\jdk1.8.0\bin\java.exe" 
Thread: 1
 Thread: 3
 Thread: 2

Tags: Java Interview Multithreading thread pool

Posted on Thu, 14 Oct 2021 18:08:02 -0400 by plautzer