问题来源:
阿里巴巴开发手册并发编程这块写有一条:线程池不允许使用Executor去创建,而是通过ThreadPoolExecutor的方式创建.
线程池的优点:
减少内存资源的消耗.
提高请求处理速度
避免出现OOM
Executor创建线层的方式:
创建返回 ThreadPoolExecutor 对象
创建返回 ScheduleThreadPoolExecutor对象
创建返回ForkJoinPool对象
ThreadPoolExecutor的构造函数有四个,但最终调用的都是同一个
Executor 创建返回ThreadPoolExecutor对象的方法共三种:
Executors.newCachedThreadPool :创建可缓存的线程池
特点:核心线程数0,工作队列SynchronizedQueue是一个不存储元素的队列,可以理解为里面永远是满的,最终会创建非核心线程来执行任务.非核心线程空闲回收时间为60s因为Integer.MAX_VALUE非常大,可以认为可以无限制的创建,所以在资源有限的情况下,容易造成OOM
Executors:newSingleThreadExecutor:创建一个单线程的线程池
特点:只有一个核心线程,超过核心线程数,会放入队列中,LinkedBlockingQueue是长度为Integer.MAX_VALUE,所以可以认为无界,那往队列里面插入任务,容易造成OOM.因为无界,所以,最大线程数和空闲时间这两个参数是无效的.
Executor.newFixedThreadPool:创建固定长度的线程池
特点:固定的核心线程池由用户传入.这个和SingleThreadExecutor相似,只是核心线程数不同,所以,在大量线程时容易造成OOM
小结:
FixedThreadPoolExecutor和SingleThreadExecutor可能会因为大量请求堆积而造成OOM
CacheThreadPoolExecutor 可能会因为大量创建线程而造成OOM
自己定义ThreadPoolExecutor
ThreadPoolExecutor threadPool=
new ThreadPoolExecutor(5, //核心线程数
10, //最大池的大小
30L,//空闲线程保持时间30
TimeUnit.SECONDS,//时间单位秒
new ArrayBlockingQueue(5),//阻塞线程
new RejectedExecutionHandler() {//拒绝服务助手 自己定义拒绝策略
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("线程数超过了线程池的容量,拒绝执行任务-->"+r);
}
});
手动创建一个线程池,用到的是ThreadPoolExecutor类的六个参数的构造方法
以上面的方法为例:
我们是设置核心线程池数5个,最大线程池10个,线程空闲时间30秒,长度为5的阻塞队列,和拒绝服务助手运行时
运行时,首先用核心线程池来调度线程有新的任务,先用核心线程来处理.
第一种情况,核心线程数没有达到5个,那么有任务进来就会创建新的线程,直到有5个核心线程
第二种情况,已经有5个核心线程,这时候有任务来,先看有没有空闲的核心线程,有的话就用核心线程,没有就把它放进队列中
等待有空闲的核心线程,再把任务从队列中take出来,给空闲核心线程
在队列中,队列为空和队列满都是阻塞状态
第三种情况,核心线程已经满了,队列中也满了,就会创建临时线程,来处理任务,运行一段时间后,
这时候如果有核心线程或是临时线程空闲,线程池就会对这些线程,看其是否达到了线程空闲时间
达到了线程空闲时间的线程,就会被销毁,他会把没执行完的临时线程变为核心线程,
执行完的核心线程和临时线程被销毁,为了保持核心线程数是5
第四种情况,核心线程已经满了,队列中也满了,临时线程也满了,就会调用拒绝服务助手,提示报错.
注意:
ThreadPoolExecutor 会根据核心线程池数和最大大小,来自动调整
当我们用execute(Runnable)提交任务小于核心线程数时就是第一种情况,优先创建新线程直到等于核心线程数
当我们核心线程没有空闲,队列也满了,这时就会创建临时线程,但临时线程数+核心线程数不能超过最大大小
如果核心线程数和最大大小设置相等,则是创建了固定大小的线程池,
如果最大大小设置特别大(像Integer.MAX_VALUE),这表示没有上限,(但也要根据CPU,很为这很吃CPU)
一般时候,我们根据构造来设置核心线程池和最大大小,但也可以调用方法来设置.
如果使用Executor的静态方法创建ThreadPoolExecutor对象可以使用Semaph偶热对任务的执行进行限流避免出现OOM