1. Benefits of thread pools
- Reuse threads in the thread pool to avoid the performance overhead associated with thread creation and destruction.
- It can effectively control the maximum number of concurrent threads in the thread pool and avoid the blocking phenomenon caused by a large number of threads snatching system resources.
- Thread can be simple management, and provide periodic execution and specified interval cycle execution and other functions.
A link to the
- The lock
2. Principle analysis
2.1 Executor
There is only one excute method
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
Copy the code
2.2 public interface ExecutorService extends Executor
ExecutorService is an Executor subinterface that adds a number of common methods of thread control that will be the mainstay of thread pools.
2.3 AbstractExecutorService
AbstractExecutorService is an abstract class.
2.4 ThreadPoolExecutor
AbstractExcutor is an AbstractExcutor concrete implementation class.
Let’s take a look at its constructor
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null* /public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
Copy the code
This is the first way to pass in blockingQueue.
Here’s the second way
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default rejected execution handler.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
Copy the code
The third way
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
Copy the code
The fourth way
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
Copy the code
Constructor parameter description
corePoolSize
Number of core threads. By default, core threads are always alive, even when idle, and are not restricted by keepAliveTime. Unless allowCoreThreadTimeOut is set to true.
maximumPoolSize
The maximum number of threads that a thread pool can hold. Threads that exceed this number will be blocked. This value is not valid when the task queue is a LinkedBlockingDeque with no set size.
keepAliveTime
The idle timeout of a non-core thread, beyond which it is reclaimed.
unit
Specify the unit of keepAliveTime, such as timeunit.seconds. This applies to corePoolSize when allowCoreThreadTimeOut is set to true.
workQueue
A task queue in a thread pool. There are three kinds of commonly used queue, SynchronousQueue will, LinkedBlockingDeque, ArrayBlockingQueue.
threadFactory
Thread factory, which provides the ability to create new threads. ThreadFactory is an interface with only one method
public interface ThreadFactory {
Thread newThread(Runnable r);
}
Copy the code
RejectedExecutionHandler
RejectedExecutionHandler is also an interface with only one method
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable var1, ThreadPoolExecutor var2);
}
Copy the code
Thread pool rules
Queues used by thread pools
BlockingQueue
Fifo queue
synchronousQueue
Thread-safe queues, where there is no fixed cache. ==SynchronousQueue has no limit ==. Because he doesn’t keep these tasks at all, he just hands them off to the thread pool. It is also used by OKHTTP to throw exceptions when the number of tasks exceeds the maximum number of threads
PriorityBlokingQueue
Unordered, can be sorted by priority. The object executed needs to implement Compareable
Okhttp uses SynchronousQueue.
All of the following assume that the task queue has no size limit:
- If the number of threads <= the number of core threads, a core thread is started directly to execute the task and is not queued.
- If the number of threads > the number of core threads, but <= the maximum number of threads, and the task queue is LinkedBlockingDeque, tasks exceeding the number of core threads are queued in the task queue.
- If the number of threads is greater than the number of core threads, but <= the maximum number of threads, and the task queue is SynchronousQueue, the thread pool creates new threads to execute the task, and these tasks are not placed in the task queue. These threads are non-core threads and are cleared when the idle time reaches the timeout period after the task is completed.
- If the number of threads > the number of core threads, and > the maximum number of threads, when the task queue is LinkedBlockingDeque, the tasks that exceed the number of core threads are queued in the task queue. When the task queue is LinkedBlockingDeque and there is no size limit, the maximum number of threads in the thread pool is invalid. The maximum number of threads in the thread pool cannot exceed the number of core threads.
- If the number of threads > the number of core threads, and > the maximum number of threads, when the task queue is SynchronousQueue, an exception will be thrown because the thread pool refuses to add tasks
The task queue size is limited
- == When LinkedBlockingDeque is full == new tasks are created to execute directly, and exceptions are thrown when the number of threads created exceeds the maximum number.
- ==SynchronousQueue has no limit ==. Because he doesn’t keep these tasks at all, he just hands them off to the thread pool. When the number of tasks exceeds the maximum number of threads, an exception is thrown.
Classification of thread pools
1. FixedThreadPool
Created by Executors’ newFIxedThreadPool method, it’s a thread pool with a fixed number of threads that don’t recycle when they’re idle unless the thread is shut down. When all threads are active, new tasks wait until a thread is free. Because FixedThreadPool has only core threads and none of these core threads are recycled, this means it can respond to requests from the outside world more quickly. There are only core threads in a FixedTHreadPool, and these core threads have no timeout mechanism, and the task queue has no size limit
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISENDS,new LinkedBlockingQueue<Runnable>());
}
Copy the code
2. CachedTHreadPool
- This is a thread pool with an indefinite number of threads, only non-core threads, and the maximum number of threads is integer.max_value. Since integer. MAX_VALUE is a maximum number, which is essentially the same as the maximum number of threads that can be arbitrarily large, the pool creates new threads to handle tasks when all the threads in the pool are active. Otherwise, idle threads are used to process new tasks.
- All idle threads in the thread pool have a timeout mechanism. The timeout duration is 60 seconds, after which idle threads are reclaimed. Unlike FixedTHreadPool, CacheThreadPool’s task queue is essentially an empty collection, which causes any task to be executed immediately.
- This type of thread pool is better suited for performing a large number of less time-consuming tasks. When the entire thread pool is idle, threads in the thread pool will timeout and be stopped. There are actually no threads in the CachethreadPool. It takes up almost no system resources.
public static ExecutorService newCachedThreadPool(a){
return new ThreadPoolExecutor(0,INterger.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
Copy the code
3. ScheduledThreadPool
- The number of core threads is fixed, while there is no limit to the number of non-core threads, and when non-core threads are idle, they are immediately recycled. ScheduledThreadPool is mainly used to execute scheduled tasks and repetitive tasks with fixed cycles.
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize,Integer.MAX_VALUE,0,NANOSECONDS,new DelayedWorkQueue());
}
Copy the code
4 SingleThreadExecutor
- Created by Executor’s newSingleThreadExecutor method. This type of thread pool has only one core thread inside it, which ensures that all tasks are executed sequentially in the same thread. The SingleThreadExector
reference
csdn