一、线程池的核心参数
通过线程池源码来分析线程池,有几个关键的参数:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

corePoolSize 表示核心线程数,线程池运行中保持核心线程的数量,自己定义,刚创建线程池时,里面的核心线程数是0,随着任务添加,达到了核心线程数,当任务执行完以后,线程池里面的线程数会一直维持在设置的核心线程数,问题点来了,为什么不释放呢? 其实是已经是空闲线程可以再次给新的任务分配进来重复的使用;
maximumPoolSize 表示最大线程数,当线程池中的核心线程数达到上限时,新来的任务会放到队列中,直到队列满了,就会判断是否达到了最大线程数,如果没达到就创建新的线程,否则执行拒绝策略,那么拒绝策略又有几种呢?我们等下再来讲解;
keepAliveTime 我们刚刚的场景说如果队列满了会判断是否达到最大线程数,那当线程数达到最大并且空闲下来以后刚刚扩容的这部分**(maxumumPoolSize-corePoolSize)**多出来的线程怎么回收呢,这里keepAliveTime就代表这部分线程的存活时间,在执行完任务以后,超过存活时间的会被回收;
workQueue 任务队列,当线程池的线程达到核心线程数以后,新来的任务统统排队进workQueue,那这里有疑问,这个workQueue 有没有一种设计是设计成多个任务队列的? 当然有的,接下来我们开始学习java线程池的几种类型;

那么线程池如何配置参数比较合适呢?
一般要根据任务需求来看,首先要知道CPU核数,这里比如有4颗,那么接下来分两种:
1.CPU密集型
这种是指线程池的任务需要大量的运算,并且没有阻塞,一直在压榨CPU的性能,这种类型的任务一定是在多核的CPU上跑的,如果是单核,你怎么加速都没用,CPU的总算力是固定的,一般配置CPU数量+1个线程的线程池大小
2.IO密集型
这种高IO的任务类型需要配置尽可能更多的线程,如CPU核数*2,有一个公式比较合理:
CPU核数/(1-阻系数),比如8核CPU 8/(1-0.9) = 80个线程数 阻塞系数范围:0.8~0.9

二、java线程池的类型及如何选择
通过查看源码,我们发现java中存在以下几种线程池:
1.public static ExecutorService newFixedTreadPool()
2.public static ExecutorService newWorkStealingPool()
3.public static ExecutorService newSingleThreadExecutor()
4.public static ExecutorService newCachedThreadPool()
5.public static ScheduledExecutorService newScheduledThreadPool()

下面分别解释每一种线程池特点和使用场景:
1.public static ExecutorService newFixedThreadPool()
创建一个固定线程数量,可重用的线程池
2.public static ExecutorService newWorkStealingPool()
jdk1.8新引进的线程池,创建持有足够线程的线程池来并行,通过使用多个队列减少竞争,如果不传参数,则默认设定为cpu的数量,底层调用的是ForkJoinPool线程池
3.public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的线程池,保证所有任务按照指定的顺序执行(FIFO,LIFO,优先级),当要求进程限制时,可以进行使用
4.public static ExecutorService newCachedThreadPool()
这是一个可缓存线程池,可以灵活的回收空闲线程,无可回收线程时,新建线程 ;线程空闲时终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资
源,底层调用的是ThreadPoolExecutor方法
5.public static ScheduledExecutorService newScheduledThreadPool()
创建一个可定期或者延时执行任务的线程池

各种线程池应用场景
1.FixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于可以预测线程数量的业务中,或者服务器负载较重,对当前线程数量进行限制。
2.newWorkStealingPool:创建一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用cpu数量的线程来并行执行,适用于大耗时的操作,可以并行来执行
3.SingleThreadPool:创建一个单线程的线程池,适用于需要保证顺序执行各个任务,并且在任意时间点,不会有多个线程是活动的场景。
4.CachedThreadPool:用来创建一个可以无限扩大的线程池,适用于服务器负载较轻,执行很多短期异步任务。
5.ScheduledThreadPool:可以延时启动,定时启动的线程池,适用于需要多个后台线程执行周期任务的场景。

三、跟传统的new一个Thread比有什么差异
new Thread的弊端如下:
1.每次new Thread新建对象性能差。
2.线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
3.缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
1.重用存在的线程,减少对象创建、消亡的开销,性能佳。
2.可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
3.提供定时执行、定期执行、单线程、并发数控制等功能。