线程池ThreadPoolExector
今天遇到的一个知识点,有关线程池的,记录一下:
当时调用的是这个构造方法,所以就拿着这个构造方法入题吧!
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueueworkQueue) { 6 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 7 Executors.defaultThreadFactory(), defaultHandler); 8 }
先进行参数介绍:
corePoolSize:线程池维护的核心线程数,可以allowCoreThreadTimeOut(true) 设置核心线程有效时间
maximumPoolSize:线程池中允许存在的最大线程数
keepAliveTime:线程池中超过 corePoolSize 数目的空闲线程最大存活时间;当阻塞队列为LinkedBlockingQueue且没有设置大小时,此值无效。
unit:超额线程的空闲存活时间的单位
workQueue:阻塞队列
Executors.defaultThreadFactory():当需要创建一个新的线程时,使用这个参数来创建
defaultHandler:饱和策略,默认为AbortPolicy(直接丢掉)
一、线程池中线程的创建和任务的执行规则
1)当线程池中的线程数量低于核心线程数(corePoolSize)的时候,提交的任务会自动创建thread来处理,无需检查线程池中是否有空闲的线程。
2)当任务数量大于核心线程数(corePoolSize),但又少于maximumPoolSize时,不再自动创建线程,而是将这些任务方到阻塞队列(workQueue)中,等待被执行。
3)当阻塞队列满了,此时请求的任务数量少于最大线程数(maximumPoolSize)时,会继续创建线程加速处理阻塞队列。4)当任务数量大于maximumPoolSize时,根据饱和策略决定是否向线程池中添加任务。
二、常见的阻塞队列(任务队列)
除了前面描述涉及到的四个属性和ThreadFactory之外,还有两个分别是workQueue和handler,分别是BlockingQueue和RejectedExecutionHandler类型。
BlockingQueue只是一个接口,它所表达的是当队列为空或者已满的时候,需要阻塞以等待生产者/消费者协同操作并唤醒线程。其有很多不同的具体实现类,各有特点。有的可以规定队列的长度,也有一些则是无界的。
排队策略:
1) SynchronousQueue(直接提交):CachedThreadPool使用的是这个BlockingQueue,它将任务直接提交给线程而不保持它们。如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。通常要求无界 maximumPoolSizes以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
适用场景:此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。
2)LinkedBlockingQueue(无界队列):FixedThreadPool和SingleThreadExecutor使用的是这个BlockingQueue,当所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过corePoolSize。因此,maximumPoolSize 的值也就无效了。
适用场景:当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列
3)ArrayBlockingQueue(有界队列):当使用有限的 maximumPoolSizes 时,有界队列有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
当然,开发者也可以定制ThreadPoolExecutor时使用ArrayBlockingQueue有界队列。
对于任务丢弃,ThreadPoolExecutor以内部类的形式实现了4个策略。分别是:
(1)CallerRunsPolicy:提交任务的线程自己负责执行这个任务。即不会创建新的线程,就在主线程中执行这个任务;
(2)AbortPolicy:使Executor抛出异常,通过异常做处理。
(3)DiscardPolicy:丢弃请求被拒绝的任务(discards therejected task)。
(4)DiscardOldestPolicy:丢弃掉队列中最早加入的任务,即后面的任务会挤走前面的任务。从而最终被执行的是末尾提交的任务。
在调用构造方法时,参数中未指定RejectedExecutionHandler情况下,默认采用AbortPolicy。
————————————————
原文链接:https://blog.csdn.net/xifens/article/details/41879515