JAVA thread pool ThreadPoolExecutor study notes

ThreadPoolExecutor

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

The number of core threads in the thread pool. When submitting a task, the thread pool creates a new thread to execute the task until the current number of threads is equal to corePoolSize; if the current number of threads is corePoolSize, the tasks that continue to submit are saved in the blocking queue, waiting to be Execute; if the prestartAllCoreThreads() method of the thread pool is executed, the thread pool will create and start all core threads in advance;

  • maximumPoolSize

The maximum number of threads allowed in the thread pool. If the current blocking queue is full and the task continues to be submitted, a new thread is created to execute the task, provided that the current number of threads is less than maximumPoolSize;

  • keepAliveTime

The survival time of the thread when it is idle, that is, the time that the thread continues to survive when there is no task execution; by default, this parameter is only useful when the number of threads is greater than corePoolSize;

  • unit

The unit of keepAliveTime;

  • workQueue

A blocking queue used to save tasks waiting to be executed, and tasks must implement the Runable interface. The following blocking queues are provided in JDK:

  1. ArrayBlockingQueue: Bounded blocking queue based on array structure, sorting tasks by FIFO;
  2. LinkedBlockingQuene: Blocking queue based on linked list structure, sorting tasks according to FIFO, the throughput is usually higher than ArrayBlockingQuene;
  3. SynchronousQuene: A blocking queue that does not store elements, each insert operation must wait until another thread calls the remove operation, otherwise the insert operation will always be blocked, and the throughput is usually higher than LinkedBlockingQuene;
  4. priorityBlockingQuene: unbounded blocking queue with priority;

  5. threadFactory

The factory for creating threads, through the custom thread factory, you can set a recognizable thread name for each newly created thread

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
  • handler

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 handle the task. The thread pool provides 4 strategies:

  1. AbortPolicy: throw an exception directly, the default policy;
  2. CallerRunsPolicy: Use the thread where the caller is located to execute the task;
  3. DiscardOldestPolicy: Discard the top task in the blocking queue and execute the current task;
  4. DiscardPolicy: Discard the task directly;

Of course, you can also implement the RejectedExecutionHandler interface according to the application scenario, and customize the saturation strategy, such as logging or tasks that cannot be processed by persistent storage.

Knowledge point

  • maximumPoolSize cannot be smaller than corePoolSize
  • Executors.newFixedThreadPool(); corePoolSize = maximumPoolSize

Operating principle:

  1. When the thread pool is smaller than corePoolSize, the newly submitted task will create a new thread to execute the task, even if there are idle threads in the thread pool at this time;
  2. When the thread pool reaches corePoolSize, the newly submitted task will be put into the workQueue, waiting for the task in the thread pool to be scheduled and executed;
  3. When the workQueue is full and the maximumPoolSize>corePoolSize, the newly submitted task will create a new thread to execute the task;
  4. When the number of submitted tasks exceeds the maximumPoolSize, the newly submitted tasks are processed by RejectedExecutionHandler;
  5. When the thread pool exceeds corePoolSize threads and the idle time reaches keepAliveTime, the idle threads are closed;
  6. When allowCoreThreadTimeOut(true) is set, the corePoolSize thread in the thread pool will also be closed when the idle time reaches keepAliveTime;

Example:

It doesn't mean that the first task will be executed first. Assuming that the queue size is 10, corePoolSize is 3, and maximumPoolSize is 6, then when 20 tasks are added, the order of execution is as follows: tasks 1, 2, and 3 are executed first, and then tasks 4-13 are put into the queue. When the queue is full, tasks 14, 15, and 16 will be executed immediately, while tasks 17~20 will throw an exception. The final order is: 1, 2, 3, 14, 15, 16, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13

flow chart:
write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325674777&siteId=291194637