我们都了解线程池的作用,这里不多做赘述。

首先来看线程池的构造函数:

public ThreadExecutor(int corePoolSize, //线程池中的线程数
    		    int maximumPoolSize, //线程池中的最大线程数
    		    long keepAliveTime, //线程数超过指定数值后,多余的空闲线程的存活时间
    		    TimeUnit unit, //线程池维护线程所允许的空闲时间的单位
    		    BlockingQueue<Runnable> workQueue, //被提交但未被执行的任务等待队列
    		    ThreadFactory threadFactory, //线程工厂,用于创建线程
                RejectedExecutionHandler handler)  //拒绝策略,当提交的任务太多,不够线程处理后,如何拒绝任务

我们看到线程池构造函数有7个参数,参数的作用如上图注释。

线程池中维护的任务队列有许多不同功能的实现,今天我们学习以下四种:

1.直接提交队列:使用的是SynchronousQueue实现的队列。提交到这个队列的任务不是真的保存在队列中,而是立即将任务提交给线程执行,如果线程池中没有线程,则立即创建线程执行,如果线程池中线程数大于最大线程数,则会执行拒绝策略,任务拒绝执行。

2.有界的任务队列: 使用的是ArrayBlockingQueue实现的队列。按照先进先出的算法处理任务。使用它时必须设定一个最大容量参数,当有任务提交到线程池中,首先判断线程池中线程数如果小于核心线程数,则立即创建新线程执行任务,若大于核心线程数则将任务提交到任务队列。如果任务队列满了,再创建新的线程执行任务。直到线程数达到最大线程数。

3.无界任务队列:使用的是LinkedBlockingQueue实现的队列。按照先进先出的算法处理任务。使用时和有界队列正好相反,任务队列没有固定容量,如果线程池中线程大于核心线程数,会将任务一直提交到任务队列,直到内存耗尽。

4.无界优先任务队列:PriorityBlockingQueue实现的队列。不是按照先进先出的算法执行,而是按照任务的优先级进行执行。

如何实现不同功能的线程池的呢?

1.newFixedThreadPool 固定线程数线程池

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

我们看到,ThreadPoolExecutor的构造函数,核心线程数和最大线程数被设置成大小一样,第三个参数,线程存活时间设置成0L,意思是当线程池中有线程空闲时,立刻被停止。第四个参数,使用无界队列作为任务队列,意思是当线程数大于核心线程数时,提交到任务队列,直到内存耗尽。

2.newSingleThreadExecutor 单线程线程池

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

ThreadPoolExecutor的构造函数,核心线程数和最大线程数被设置成1,线程存活时间0L,无界任务队列。保证只有一个线程工作。

3.newCachedThreadExecutor 可缓存线程池

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

可以看到核心线程数为0,最大线程数无穷大,存活时间60L,任务队列是直接提交队列。如果线程池中没有空闲线程,将任务提交到任务队列,直接创建线程去执行,如果空闲60s,由于核心线程数为0,则会被回收。