为什么禁用Executors创建线程池,而用ThreadPoolExecutor创建?

阿里的 Java开发手册建议线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
禁用原因:Executors创建出来的线程池使用的全都是无界队列,而使用无界队列就可以无限保存任务,因此很有可能造成OOM异常。同时在某些类型的线程池里面,使用无界队列还会导致maxinumPoolSize、keepAliveTime、handler等参数失效。

ThreadPoolExecutor

在这里插入图片描述
其中ThreadPoolExecutor表示一个线程池,Executors类扮演着线程工厂的角色,通过Executors可以取得一个拥有特定功能的线程池。ThreadPoolExecutor类实现了Executor接口,通过这个接口,任何Runnable的对象都可以被ThreadPoolExecutor线程池调度。

 public ThreadPoolExecutor(int corePoolSize,					// 线程池核心池大小
                           int maximumPoolSize,					// 线程池最大线程数
                           long keepAliveTime,	// 当线程数大于核心池大小时,多余的空闲线程等待新任务的最长时间,超过时间会被销毁
                           TimeUnit unit,						// keepAliveTime的时间单位
                           BlockingQueue<Runnable> workQueue,	// 用来存储等待执行任务的队列
                           ThreadFactory threadFactory,			// 线程工厂
                           RejectedExecutionHandler handler) 	// 拒绝策略

参数详解

corePoolSize 和 maximumPoolSize,keepAliveTime

当corePoolSize和maximunPoolSize的值均为1,keepAliveTime设置为0因为不会出现存在空闲线程的情况,这样线程池中就会一直只存在一个线程,即单线程的线程池SingleThreadExecutor,它可以保证任务顺序执行。
当corePoolSize = 0 并且 maximumPoolSize = Integer.MAX_VALUE,称为线程数大小无界的线程池CachedThreadPool,因为最大的线程数是Integer.MAX_VALUE,所以可能创建数量很多的线程导致OOM。

TimeUnit

  1. TimeUnit.DAYS // 天
  2. TimeUnit.HOURS // 小时
  3. TimeUnit.MINUTES // 分钟
  4. TimeUnit.SECONDS // 秒
  5. TimeUnit.MILLISECONDS // 毫秒

BlockingQueue

  1. ArrayBlockingQueue :由数组结构组成的有界阻塞队列。当任务队列装满时,可能将线程数提升到corePoolSize以上。
  2. LinkedBlockingQueue :由链表结构组成的有界阻塞队列。除非资源耗尽,否则无界的任务队列不存在入队失败的情况。
  3. PriorityBlockingQueue :支持优先级排序的无界阻塞队列。总是保证高优先级的任务先执行。
  4. DelayQueue: 使用优先级队列实现的无界阻塞队列。
  5. SynchronousQueue: 直接提交队列,不存储元素的阻塞队列。提交的任务不会被保存,而是总将新任务提交给线程执行。如果没有空闲的进程,则尝试创建新的进程,如果进程数量已经达到最大值,则执行拒绝策略。
  6. LinkedTransferQueue: 由链表结构组成的无界阻塞队列。
  7. LinkedBlockingDeque: 由链表结构组成的双向阻塞队列。

ThreadFactory

用户可以实现它自定义自己的线程启动方式,可以设置线程名称、类型以及优先级等属性。其中也只是有一个newthread方法。

RejectedExecutionHandler

  1. ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常,也是线程池默认的策略。
  2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

线程池执行流程

  1. 先判断线程池中线程的数量是否小于核心线程数,如果小于corePoolSize,就创建新的线程去执行任务;否则就进入到下面流程。
  2. 判断任务队列是否已经满了,即:判断workQueue有没有满,如果没有满,就将任务添加到任务队列中;如果已经满了,就进入到下面的流程。
  3. 再判断如果新创建一个线程后,线程数是否会大于最大线程数,如果大于maximumPoolSize,则进入到下面的流程;否则就创建一个新的线程来执行任务。
  4. 执行拒绝策略,即执行handler的rejectedExecution()方法。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值