线程池基础类_ThreadPoolExecutor (JDK1.8)

ThreadPoolExecutor

简介

  ThreadPoolExecutor使用线程池执行提交的任务,还维护一些基本统计信息,例如已完成任务的数量。
  为了适应大多数场景,该方法提供了许多可调参数和钩子方法。但是推荐使用
Executors工厂方法构造实例:Executors.newCachedThreadPool(无限制线程池,具有自动线程回收),Executors.newFixedThreadPool(固定大小的线程池)和Executors.newSingleThreadExecutor(单个后台线程)。

手动配置调优指南

核心线程和最大线程数目

  ThreadPoolExecutor根据corePoolSize(请参阅getCorePoolSize)和maximumPoolSize(请参阅getMaximumPoolSize)设置的边界自动调整池大小(请参阅getPoolSize)。

  • 当一个新任务在方法execute(Runnable)中提交,并且核心线程少于corePoolSize线程运行时,即使其他工作线程处于空闲状态,也会创建一个新的线程来处理该请求。
  • 如果超过corePoolSize但小于maximumPoolSize线程运行,则仅当队列已满时才会创建一个新线程。
  • 通过将corePoolSize和maximumPoolSize设置为相同,可以创建一个固定大小的线程池。
  • 通过将maximumPoolSize设置为本质上无限制的值(例如Integer.MAX_VALUE),可以允许池适应任意数量的并发任务。

通常核心和最大池大小只能在构建时进行设置,但也可以使用setCorePoolSize和setMaximumPoolSize动态更改池大小。

按需构造

  默认情况下,只有在新任务到达时,核心线程才会被创建启动,但可以通过 prestartCoreThread 或prestartAllCoreThreads方法提前启动这些线程。

创建新线程

  ThreadPoolExecutor使用ThreadFactory创建线程,默认使用Executors.defaultThreadFactory(创建的线程位于同一个ThreadGroup里,并且都使用NORM_PRIORITY优先级,非守护线程)。通过提供一个ThreadFactory,可以改变线程名、线程组、优先级、守护性质等。
  如果ThreadFactory创建线程时返回null,executor仍会继续,但可能不会执行任何任务。

存活时间

  如果当前线程数超过核心线程数,超出的线程如果空闲时间超过keepAliveTime指定的时间,则会被终止。可以通过 setKeepAliveTime(long, TimeUnit) 方法动态的修改keepAliveTime。
  设置 Long.MAX_VALUE TimeUnit.NANOSECONDS可以是超时时间生效,通过allowCoreThreadTimeOut(boolean) 方法可以设置超时是否对核心线程有效。

排队

ThreadPoolExecutor使用BlockingQueue保存任务,该队列和线程大小交互如下:

  • 如果当前线程数小于核心线程数,则Executor会创建线程用于执行任务,而不会把任务交给队列
  • 如果当前线程数大于核心线程数,则Executor会把任务交给队列,而不会创建线程
  • 如果任务无法入队,并且当前线程数小于最大线程数,则会创建线程用于执行任务
  • 如果任务无法入队,且当前线程数大于最大线程数,则该任务会被拒绝

有三种入队的策略

  1. 不存储任务的队列。比如SynchronousQueue,每一个put操作必须等待一个take操作,否则不能继续添加元素。如果没有一个线程可以立即去执行任务,则任务入队会失败。
  2. 无界队列。比如未指定长度的LinkedBlockingQueue(默认长度为Integer.MAX_VALUE),当核心线程都在运行时,新加入的任务都会入队。
  3. 有界队列。比如ArrayBlockingQueue,可以避免资源耗尽,但是很难调优控制。使用大队列和小线程池可以最大限度地减少CPU使用率,操作系统资源和上下文切换开销,但可能导致人为的低吞吐量(比如很多线程都被IO阻塞)。使用小队列通常需要较大的池,这样可以提高CPU利用率,但可能会遇到不可接受的调度开销,这也降低了吞吐量。
拒绝任务

当Executor被关闭,或者线程池和队列都达到饱和时,提交的任务会被拒绝。在这两种情况下,execute方法会调用RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) ,有四种预定义的处理策略:
1. ThreadPoolExecutor.AbortPolicy:默认策略,抛出RejectedExecutionException异常
2. ThreadPoolExecutor.CallerRunsPolicy:调用execute()方法的线程自己执行提交的任务。这提供了一个简单的反馈控制机制,将降低新任务提交的速度。
3. ThreadPoolExecutor.DiscardPolicy:任务被简单丢弃
4. ThreadPoolExecutor.DiscardOldestPolicy:如果Executor没有关闭,则队列头部的任务被删除,然后重新执行(可能会再次失败,这会导致重复执行这个逻辑)。

钩子方法

beforeExecute(Thread, Runnable) 和 afterExecute(Runnable, Throwable)会在每个任务被执行前和执行后被调用, terminated()在Executor终止的时候(无任务并且已关闭)时被调用。
如果钩子方法抛出异常,内部的工作线程可能会失败并突然终止。

队列维护

方法getQueue()允许访问工作队列以进行监视和调试。 不鼓励将此方法用于任何其他目的。 当大量排队任务被取消时,两种提供的方法,remove(Runnable)和purge可用于协助进行存储回收。

public class ThreadPoolExecutor extends AbstractExecutorService {

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值