Java线程池ThreadPoolExecutor笔记

构造ThreadPoolExecutor参数介绍

ThreadPoolExecutor提供了几个构造方法,个别参数不传的话就使用默认值,这里我们介绍包含所有参数的构造方法:
参数简介:
  1. corePoolSize 核心线程数,即线程池中保留的线程数
  2. maximumPoolSize 线程池中最大线程数,超过若线程数超过该值将触发拒绝策略RejectedExecutionHandler 
  3. keepAliveTime 当一个线程处于空闲状态是,超过keepAliveTime 长时间将终止该线程,以便池中线程数量恢复到corePoolSize大小,若线程池中数量小于corePoolSize 则该设置不起作用。
  4. unit 是一个时间枚举,表示 keepAliveTime 的单位,如 TimeUnit.SECONDS
  5. workQueue 表示存放任务的队列,比较常用是LinkedBlockingQueue、SynchronousQueue
  6. threadFactory 产生线程的工厂类,可参考默认实现Executors.DefaultThreadFactory。由于经常要在日志中打印出线程名,因此可以参考该实现来实现自定义线程名,或是使用第三方工具类。
  7. handler 拒绝策略

提交任务流程

线程池虽然提供了不同参数的方法来供外部提交任务,但最终调用的都是 ThreadPoolExecutor.execute(Runnable command) 。以下是任务提交流程:

提交任务时,根据当前线程池中的线程数量currentNum不同,流程如下:
  1. 若currentNum小于corePoolSize,则不管有没有空闲线程,都创建新的线程来执行该任务
  2. 若currentNum等于corePoolSize,但缓冲队列 workQueue未满,那么任务被放入缓冲队列,等待调度执行
  3. 若currentNum大于corePoolSize,且缓冲队列 workQueue已满,并且currentNum小于maximumPoolSize,继续创建新的线程来执行该任务
  4. 若currentNum大于corePoolSize,且缓冲队列 workQueue已满,并且currentNum等于maximumPoolSize,新提交任务由拒绝策略Handler处理

当然还是建议看看源码:

队列类型

虽然线程池要求队列必须是BlockingQueue的子类,但从上面的源码中可以到添加任务使用的是非阻塞的offer方法,该方法只会在队列满的时候直接返回false。因此不要期望当队列已满的时候,添加任务的线程会被阻塞!
  1. 无队列  通常使用 SynchronousQueue。通过JDK文档可以了解到这是阻塞队列,且队列长度为0。如果你希望添加的任务不需要“排队”,直接执行,就可以使用该队列,但要求将maximumPoolSize设置得很大以便不会触发拒绝策略
  2. 有界队列  通常使用LinkedBlockingQueue ,根据实际使用场景定义一个固定长的队列,需要综合考虑任务并发量,线程数等等
  3. 无界队列  容量很大的有界队列,如直接new LinkedBlockingQueue()返回一个长度为 Integer.MAX_VALUE 的队列

拒绝策略

ThreadPoolExecutor内部为RejectedExecutionHandler 接口实现了4种拒绝策略,强烈推荐看其源码实现!
  1. ThreadPoolExecutor.AbortPolicy 抛出抛出java.util.concurrent.RejectedExecutionException异常,默认值
  2. ThreadPoolExecutor.CallerRunsPolicy 交由调用者线程来执行任务
  3. ThreadPoolExecutor.DiscardPolicy 什么都不做,相当于抛弃该任务
  4. ThreadPoolExecutor.DiscardOldestPolicy 位于任务队列头部的任务将被删除,以便队列能加入该任务

线程池构造工具类

由于线程池的参数设置比较复杂,因此JDK推荐使用工具类java.util.concurrent.Executors来创建几种常用的线程池,我们也可以通过阅读源码来进一步加深参数的理解。
(1)创建一个固定线程数的线程池。注意这里的队列相当于一个无界队列,其长度为 Integer.MAX_VALUE

(2)创建一个线程数无上限的线程池,其线程数可以不断增加。因此这里使用了队列类型为SynchronousQueue,即无队列模式。

一定要记得在实际应用中,我们不可能将maximumPoolSize设置成Integer.MAX_VALUE,或传入长度为 Integer.MAX_VALUE的队列new LinkedBlockingQueue<Runnable>(),要是程序有bug就会导致线程数过大而压垮了线上系统,或内存溢出。对待线上系统一定要十分谨慎,保守的设置这些参数!

几个API说明

一般人会使用setCorePoolSize、setMaximumPoolSize来修改线程池中允许的线程数,来达到并发线程数控制的目的;这时通过改变corePoolSize是没用的,只有通过改变maximumPoolSize才可以。corePoolSize只是当线程池空闲时池中线程的最小保有量。但是,以上做法是不建议使用的,建议在线程池之外独立实现并发控制。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值