此前在项目中有如下场景:可同时开启多个任务,但要控制同时并发的任务数。
这种场景刚好可借用ThreadPoolExecutor阻塞队列线程池来实现,先来看看其构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize 线程池中持有的最小线程数
- maximumPoolSize 线程池中允许持有的最大线程数
- keepAliveTime 当线程数大于corePoolSize时,空闲线程被回收前最大存活时间
- unit 空闲线程被回收前最大存活时间的时间单位
- workQueue 请求任务运行前的缓冲队列
- threadFactory 线程工厂
- handler 线程池对拒绝任务的处理策略
当线程加入时:
1. 如果请求任务数小于corePoolSize则线程立即执行请求任务
2. 如果线程池中的线程数已达corePoolSize,则请求任务加入workQueue等待
3. 如果workQueue已满,且线程池中的总线程数未超过maximumPoolSize,则新建线程执行请求任务
4. 如果线程池中的线程数已达maximumPoolSize,则新来的任务按照handler 的策略进行处理。
考虑如下场景(任务运行时间假设无限长):
总任务数: 7
corePoolSize: 2
maximumPoolSize: 4
workQueue: 2
- 总线程数小于corePoolSize:首先任务1和任务2将立即投入运行;此时线程数为2
- 线程数已达corePoolSize:任务3和任务4将进入workQueue等待
- workQueue已满且线程池中的总线程数为2未超过maximumPoolSize:新建线程运行任务5和任务6;此时线程数为4
- 线程数已达maximumPoolSize:任务7将按照handler策略被拒绝
基于ThreadPoolExecutor创建的几个常用线程池:
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
newCachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }