在《阿里巴巴java开发手册》中写到,线程池不允许使用Executors 去创建,而是通过 ThreadPoolExecutor 的方式。
Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
那ThreadPoolExecutor类如何使用。
首先是ThreadPoolExecutor的构造函数

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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

构造函数参数含义:
corePoolSize:指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去。
maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量。
keepAliveTime:当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁。
unit:keepAliveTime的单位。
workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种。
threadFactory:线程工厂,用于创建线程,一般用默认即可。
handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务
一、workQueue任务队列
一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列
1、直接提交队列:设置为SynchronousQueue队列,SynchronousQueue是一个特殊的BlockingQueue,它没有容量,每执行一个插入操作就会阻塞。

public class ThreadTest implements Runnable{
        private int num;
        ThreadTest(int i){
            this.num = i;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"任务"+num);
        }
    }
    @Test
    public void threadTest(){
        ExecutorService pool = new ThreadPoolExecutor(1, 4, 2000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        for(int i = 1;i<10;i++){
            pool.execute(new ThreadTest(i));
        }
    }

运行结果:
pool-1-thread-1任务1
pool-1-thread-3任务3
pool-1-thread-2任务2
pool-1-thread-4任务4

java.util.concurrent.RejectedExecutionException: Task com.Alm.blog.service.controller.BlogController$ThreadTest@3d51f06e rejected from java.util.concurrent.ThreadPoolExecutor@7ed7259e[Running, pool size = 4, active threads = 0, queued tasks = 0, completed tasks = 4]

可以看到,当任务队列为SynchronousQueue时,没有容量,提交的任务会被马上执行,并且执行完后当前线程阻塞,不会复用,所以当创建的线程数大于maximumPoolSize时,直接执行了拒绝策略抛出异常。
一般使用SynchronousQueue都会要求为无界(maximumPoolSize=Integer.MAX_VALUE)。
2.有界的任务队列:一般使用ArrayBlockingQueue来实现

ExecutorService pool = new ThreadPoolExecutor(1,3, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

使用ArrayBlockingQueue有界任务队列,若有新的任务需要执行时,线程池会创建新的线程,直到创建的线程数量达到corePoolSize时,会将新的任务加入到等待队列中。这里等待队列的任务数量设置为3,若等待队列已满,即超过ArrayBlockingQueue初始化的容量,则继续创建线程,直到线程数量达到maximumPoolSize设置的最大线程数量,若大于maximumPoolSize,则执行拒绝策略。
3.无界的任务队列:一般使用LinkedBlockingQueue来实现

ExecutorService pool = new ThreadPoolExecutor(1,3, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

使用无界的任务队列,线程池的任务队列可以无限制添加新任务,而线程池创建的最大线程数就是corePoolSize设置的数量,这种情况下maximumPoolSize设置的值是不会生效的,就算等待队列中有许多未执行的任务,线程池的数量达到了corePoolSize的值后也不会增加新的线程。
4.优先任务队列:一般使用PriorityBlockingQueue来实现

public static class ThreadTest implements Runnable,Comparable<ThreadTest>{
        private int num;
        ThreadTest(int i){
            this.num = i;
        }
        //顺序
        //public int compareTo(ThreadTest o) {
        //    return  this.num-o.num;
        //}
        // 倒序
        public int compareTo(ThreadTest o) {
            return  this.num>o.num?-1:1;
        }
        @Override
        public void run() {
            try{
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"任务"+num);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
         ExecutorService pool = new ThreadPoolExecutor(1,3, 1000, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
         for(int i = 1;i<10;i++){
             pool.execute(new ThreadTest(i));
         }
    }

运行结果如下:
pool-1-thread-1任务1
pool-1-thread-1任务9
pool-1-thread-1任务8
pool-1-thread-1任务7
pool-1-thread-1任务6
pool-1-thread-1任务5
pool-1-thread-1任务4
pool-1-thread-1任务3
pool-1-thread-1任务2
因为corePoolSize设置为1,且线程休眠了1秒,则除了1以外其他任务全部进入了等待队列中,然后根据指定的按优先级规则进行了重新排列执行,且线程池的线程数一直为corePoolSize。