目录
为什么要用线程池
- 降低频繁创建销毁线程带来的性能损耗,以达到线程重复利用
- 提高线程的可管理性
ThreadPoolExecutor参数详解
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
-
corePoolSize 核心线程数。创建后会有这么多条核心线程,核心线程即使空闲下来也不会销毁;
-
maximumPoolSize 最大线程数
-
keepAliveTime 线程空闲的存活时间。线程如果空闲超过keepAliveTime,且是非核心线程,会销毁线程;
-
unit 存活时间keepAliveTime的单位
-
workQueue 阻塞队列
- ArrayBlockingQueue 数组阻塞队列。根据FIFO排序,属有界队列。
- LinkedBlockingQueue 链表阻塞队列。根据FIFO排序,默认容量为Integer.MAX_VALUE,可指定大小,吞吐量比ArrayBlockingQueue 高。
- SynchronousQueue 同步队列。向该队列放入一个任务,必须要有空闲线程去取走一个任务才可放入,如果没有空闲线程取走就创建新线程,创建不了就执行拒绝策略。
- PriorityBlockingQueue 带优先级的无界阻塞队列。
-
threadFactory 创建线程的工厂,可用于设置线程的名称
-
handler 拒绝策略。当workQueue队列满了,且线程数已经达到最大,新来的任务会由该策略进行处理;
线程池提供了4种策略:- AbortPolicy 抛出异常
- CallerRunsPolicy 由调用者当前线程执行
- DiscardPolicy 丢弃任务
- DiscardOldestPolicy 丢弃最早的任务
此外,我们还可以通过实现RejectedExecutionHandler接口,自定义拒绝策略。
ThreadPoolExecutor原理
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
- 线程池创建后,当任务提交到线程池时:
- 当线程数 <= corePoolSize ,会先用核心线程来执行任务,否则任务会放进workQueue队列中;
- 当workQueue也放满任务,且maximumPoolSize>corePoolSize,会创建新的线程执行任务;
- 当线程数达到maximumPoolSize,且workQueue也放满任务,新来的任务会由RejectedExecutionHandler处理;
- 当非核心线程空闲(指空闲keepAliveTime这么长时间)后,会销毁线程;
为什么阿里推荐自定义线程池
Executors提供的线程池各有优劣,自定义一个统一的线程池可以减少线程池的滥用问题,方便排除监控
Executors提供的5种线程池
newFixedThreadPool
固定线程数线程池,这种线程池的核心线程数和最大线程数都是一样的,阻塞队列用的是LinkedBlockingQueue,由于是无界队列,所以当任务数过大时,阻塞队列可能发生OOM
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor
单线程线程池,可见和newFixedThreadPool大体一样,只是核心线程数和最大线程数都是1,其他都一样。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool
可缓存线程池,这种线程池使用要注意最大线程数为Integer.MAX_VALUE,有可能发生因为创建太多的线程而OOM。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newScheduledThreadPool
定长线程池,支持延迟或周期性任务。最大线程数是Integer.MAX_VALUE,且使用DelayedWorkQueue延迟队列,同时也是无界队列,任务过多也有可能导致OOM。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
newSingleThreadScheduledExecutor
原理和newScheduledThreadPool一样
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}