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接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务