JDK中有四种线程池,分别是FixedThreadPool,SingleThreadExecutor,CachedThreadPool,ScheduledThreadPool,他们都依赖一个核心类ThreadPoolExecutor
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- corePoolSize:池中线程的数量保持,即使这些应用程序处于空闲状态,除非核心线程时间被设置
- maximumPoolSize:线程池中允许的最大数量
- keepAliveTime:当线程的数量大于核心线程数,空闲线程终止之前将等待新的任务的最长时间,一旦超过这个时间,空闲的线程将被回收,直至线程数等于核心线程数
- unit:keepAliveTime的时间单位
- workQueue:队列用于执行任务之前。这个队列只持有excute方法提交的Runnable任务
FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
FixedThreadPool是固定线程数的线程池,核心线程等于最大线程数,超过核心线程数空闲的线程马上被回收。任务队列使用的是LinkedBlockingQueue,LinkedBlockingQueue的大小是Integer.MAX_VALUE。
SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
SingleThreadExecutor是单一线程数的线程池,核心线程和最大线程数等于1,超过核心线程数空闲的线程马上被回收。任务队列使用的是LinkedBlockingQueue,LinkedBlockingQueue的大小是Integer.MAX_VALUE。
CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
CachedThreadPool是缓存线程数的线程池,核心线程为0,最大线程数为Integer.MAX_VALUE,超过核心线程数空闲的线程超过60秒会被回收。任务队列使用的是SynchronousQueue,SynchronousQueue作为主线程池的工作队列,它是一个没有容量的阻塞队列。每个插入操作必须等待另一个线程的对应移除操作。这意味着,如果主线程提交任务的速度高于线程池中处理任务的速度时,CachedThreadPool会不断创建新线程。
ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
ScheduledThreadPool是执行定时任务的线程池,核心线程为传入值,最大线程数等于Integer.MAX_VALUE,超过核心线程数空闲的线程马上被回收。任务队列使用的是DelayedWorkQueue,DelayedWorkQueue实现了LinkedBlockingQueue的接口,大小是Integer.MAX_VALUE。
在日常的开发中,不建议直接使用Executors直接去创建以上这些线程池,而是自己通过显式的ScheduledThreadPoolExecutor去创建
Executors各个方法的弊端:
1.newFixedThreadPool和newSingleThreadPool:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2.newCachedThreadPool和newScheduledThreadPool
主要问题是线程数最大数是Integer.MAX_VALUE,可能会常见数量非常多的线程,甚至OOM
建议使用创建的方法是
ExecutorService pool = new ThreadPoolExecutor(5,200,
0L,TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
当任务超过队列的大小时,需要执行一些拒绝的策略
- CallerRunsPolicy:只要当前线程没有被关闭就继续执行
- AbortPolicy:直接抛出RejectedExecutionException异常带有线程信息
- DiscardPolicy:直接扔掉这个任务
- DiscardOldestPolicy:扔掉最老的,执行新加入的