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;
}
这是线程池最核心的构造函数,搞明白这些参数的含义,线程池就算搞明白了一半。
corePoolSize 核心线程数,当你提交一个任务时候,如果没有达到核心线程数,就开辟一个新线程来执行,这个线程为核心线程
maximumPoolSize 最大线程数,最大线程数 = 核心线程数+非核心线程数
keepAliveTime 空闲存活时间,这个代表非核心线程如果没有任务多久之后被清除掉。对应的线程池内部有个私有属性allowCoreThreadTimeOut这个是boolean类型,默认为false,代表空闲状态下的核心线程可以一直存活,如果为true那么核心线程的待遇和非核心是一样的
unit 时间单位,数学老师说没有单位的结果都是没有意义的,时间也是,这个是确定keepAliveTime这个时间单位的
workQueue 阻塞队列,在线程池里称为工作队列,存放任务的,具体效果根据具体阻塞队列来的,一般是array,list的阻塞队列
threadFactory 线程工厂,工厂模式大都了解一点,为了优雅的创建对象而生,那这个就是为了优雅的创建线程而生,方便记录线程个数,给线程改名字,用线程组统一管理
RejectedExecutionHandler 拒绝策略可以自己实现,默认有四种选择 ,放弃这个任务,异常,放弃旧任务执行刚刚提交的,在提交者线程中执行刚刚提交的任务
讲解了这些参数的意义,那么在实际上这些参数是怎么起作用的呢?
回到线程池的本身作用,复用线程,不需要一个任务就开辟一个新线程去执行,只需要往线程池中提交任务即可,线程池会自动派线程去执行
那么问题来了一次任务的提交的过程是什么样子?
JDK给我封装好了四个常用线程池,当你清楚上面的参数含义和流程之后这四个线程池的原理一目了然
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
核心线程,最大线程都为1,存活时间为0,时间为milliseconds,工作队列为List的阻塞队列,其他2个参数均为默认,很明显,永远只有一个核心线程,线程永远不会死,任务队列为List,永远不会满,永远不会增加非核心也就永远不会触发RejectedExecutionHandler
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
核心线程和最大线程为输入参数,其他同上,原理也很清晰,不在过多解释
newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
核心线程是0,最大线程数为最大int,60s空闲就回收线程,阻塞队列是SynchronousQueue不会保存任何任务,直接交给线程去执行,换句话说这是一直满的(其实不能这么说,相当于这样而已)这样就一直开辟新线程去执行任务(没有空闲线程的情况下),如果线程空闲下来就会60s回收掉。
newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
这个线程池继承了ThreadPoolExecutor和其他有点不同,但是还是用的是ThreadPoolExecutor的构造函数,唯一区别是工作队列的区别,队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务