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

来源:互联网 发布:linux select timeout 编辑:程序博客网 时间:2024/06/08 00:47

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 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁宝贝吐没精神怎么办 11个月的宝宝吐怎么办 二岁的宝宝吐了怎么办 十个月小孩吐了怎么办 10个月宝宝呕吐怎么办 小孩又拉又吐的怎么办 小孩子不吃饭呕吐拉肚子怎么办 小孩发烧后又吐怎么办 11个月宝宝吐了怎么办 11个月宝宝拉肚子怎么办 2岁宝宝反复呕吐怎么办 1岁半幼儿拉肚子怎么办 宝宝打嗝呕吐胃难受怎么办 3岁宝宝发烧还吐怎么办 孩子喝水都吐怎么办啊 宝宝吃多了呕吐怎么办 3岁宝宝吐怎么办才好 儿童受凉肚子疼发热呕吐怎么办 两岁宝宝半夜呕吐怎么办 两岁宝宝吐了怎么办 2岁宝宝发烧吐怎么办 2岁多宝宝呕吐是怎么办 2周岁宝宝中暑了怎么办 2岁半宝宝着凉呕吐怎么办 3岁宝宝吐了几次怎么办 一岁宝宝恶心吐怎么办 9个月宝宝一直吐怎么办 晚上冻着了呕吐怎么办 2岁宝宝一直吐怎么办 两岁宝宝门牙龋齿怎么办 两岁宝宝得龋齿怎么办 两岁宝宝长龋齿怎么办 宝宝2岁不吃饭怎么办 两岁宝宝总是吐怎么办 3岁儿童受凉呕吐怎么办 两岁宝宝四天没拉大便怎么办 两岁宝宝发烧吐怎么办 四岁宝宝吐了怎么办啊 3岁宝宝突然吐了怎么办 宝宝撑着了吐拉怎么办 2岁宝宝体温37.5怎么办