为什么不用Executor而是用ThreadPoolExecutor创建线程池

问题来源:

阿里巴巴开发手册并发编程这块写有一条:线程池不允许使用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值