JUC - ThreadPoolExecutor

创建一个ThreadPoolExecutor

ThreadPoolExecutor(
int corePoolSize, // 保留在池中的线程数,即使空闲了也保留(除非设置了{@code allowCoreThreadTimeOut})
int maximumPoolSize, // 池中允许的最大线程数
long keepAliveTime, // 当maximumPoolSize>corePoolSize时,多余空闲线程等待任务的时间
TimeUnit unit, // {@code keepAliveTime}参数的时间单位
BlockingQueue<Runnable> workQueue, // 在task执行之前暂存task.队列只接纳被 {@code execute}方法提交的{@code Runnable}task
ThreadFactory threadFactory, // 创建执行task线程的工厂
RejectedExecutionHandler handler // 如果达到线程界限或者队列容量,拒绝任务执行的处理
)

参数限制

  • 满足以下条件之一则抛出IllegalArgumentException

    • corePoolSize < 0
    • keepAliveTime < 0
    • maximumPoolSize <= 0
    • maximumPoolSize < corePoolSize
  • 抛出NullPointerException
    • threadFactory == null
    • handler == null

参数补充说明

  • corePoolSize : 如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程
  • keepAliveTime : 指该线程池中非核心线程闲置超时时长, 超过这个参数所设定的时长,就会被销毁掉, 如果设置allowCoreThreadTimeOut = true,则会作用于核心线程
  • unit : TimeUnit时间
  • maximumPoolSize : 线程总数 = 核心线程数 + 非核心线程数
  • workQueue : 当核心线程都在工作时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务
    • ArrayBlockingQueue : 构造函数一定要传大小
    • LinkedBlockingQueue : 构造函数不传大小会默认为Integer.MAX_VALUE,当大量请求任务时,容易造成内存耗尽.由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
    • SynchronousQueue : 同步队列,一个没有存储空间的阻塞队列 ,将任务同步交付给工作线程.此队列通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务
    • PriorityBlockingQueue : 优先队列
    • DelayQueue : 传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
  • threadFactory : 线程工厂(默认值Executors.defaultThreadFactory())
  • handler : 拒绝策略
    • AbortPolicy(默认) : 直接抛弃
    • CallerRunsPolicy : 拒绝这个任务,不在ThreadPoolExecutor线程池中的线程中运行,而是调用当前线程池的所在的线程去执行被拒绝的任务
    • DiscardOldestPolicy : 抛弃队列中最久的任务(最先加入队列的任务),再把这个新任务添加到队列中去。
    • DiscardPolicy : 线程池默默丢弃这个被拒绝的任务,不会抛出异常。

执行过程

  • 1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
  • 2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
  • 3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
  • 4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
  • 5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
  • 6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

Executors中常见的ThreadPoolExecutor

  • 单个线程池: Executors.newSingleThreadExecutor() || Executors.newSingleThreadExecutor(ThreadFactory threadFactory)

    • new ThreadPoolExecutor(1, 1,

      0L, TimeUnit.MILLISECONDS,

      new LinkedBlockingQueue())
    • new ThreadPoolExecutor(1, 1,

      0L, TimeUnit.MILLISECONDS,

      new LinkedBlockingQueue(),

      threadFactory)
    • 创建单个线程
  • 固定线程池: Executors.newFixedThreadPool(int nThreads) || Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
    • new ThreadPoolExecutor(nThreads, nThreads,

      0L, TimeUnit.MILLISECONDS,

      new LinkedBlockingQueue())
    • new ThreadPoolExecutor(nThreads, nThreads,

      0L, TimeUnit.MILLISECONDS,

      new LinkedBlockingQueue(),

      threadFactory);
    • 核心线程和最大线程相同,并且不过期
  • 缓存线程池: Executors.newCachedThreadPool() || Executors.newCachedThreadPool(ThreadFactory threadFactory)
    • new ThreadPoolExecutor(0, Integer.MAX_VALUE,

      60L, TimeUnit.SECONDS,

      new SynchronousQueue())
    • new ThreadPoolExecutor(0, Integer.MAX_VALUE,

      60L, TimeUnit.SECONDS,

      new SynchronousQueue(),

      threadFactory)
    • 核心线程为0,并且阻塞队列为SynchronousQueue,按需创建线程,默认过期时间60s
  • 调度线程池: Executors.newScheduledThreadPool(int corePoolSize) || Executors.newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
    • new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE,

      0, TimeUnit.NANOSECONDS,

      new DelayedWorkQueue())
    • new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE,

      0, TimeUnit.NANOSECONDS,

      new DelayedWorkQueue(),

      threadFactory)
    • 可以调度命令以在给定延迟后运行或定期执行
  • 窃取线程池: Executors.newWorkStealingPool() || Executors.newWorkStealingPool(int parallelism)
    • new ForkJoinPool

      (Runtime.getRuntime().availableProcessors(),

      ForkJoinPool.defaultForkJoinWorkerThreadFactory,

      null, true);
    • new ForkJoinPool

      (parallelism,

      ForkJoinPool.defaultForkJoinWorkerThreadFactory,

      null, true)
    • 窃取线程是ForkJoinPool的拓展(分治算法),创建一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用cpu数量的线程来并行执行,适合很耗时间的任务

参考阅读

JUC - ThreadPoolExecutor的更多相关文章

  1. 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

  2. JUC 之 ThreadPoolExecutor 的一些研究

    ThreadPoolExecutor 概述:===================================================================== 构造函数: 4个 ...

  3. Java - "JUC线程池" ThreadPoolExecutor原理解析

    Java多线程系列--“JUC线程池”02之 线程池原理(一) ThreadPoolExecutor简介 ThreadPoolExecutor是线程池类.对于线程池,可以通俗的将它理解为"存 ...

  4. juc线程池原理(二):ThreadPoolExecutor的成员变量介绍

    概要 线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理. ThreadPoolExecutor数据结构 Thread ...

  5. JUC - Monitor监控ThreadPoolExecutor

    JUC - Monitor监控ThreadPoolExecutor 一个自定义Monitor监控ThreadPoolExecutor的执行情况 TASK WokerTask class WorkerT ...

  6. JUC源码分析-线程池篇(一):ThreadPoolExecutor

    JUC源码分析-线程池篇(一):ThreadPoolExecutor Java 中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池 ...

  7. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

  8. JUC回顾之-ThreadPoolExecutor的原理和使用

    Spring中的ThreadPoolTaskExecutor是借助于JDK并发包中的java.util.concurrent.ThreadPoolExecutor来实现的.基于ThreadPoolEx ...

  9. JUC线程池之 ThreadPoolExecutor简介

    ThreadPoolExecutor简介 ThreadPoolExecutor是线程池类.对于线程池,可以通俗的将它理解为"存放一定数量线程的一个线程集合.线程池允许若个线程同时允许,允许同 ...

随机推荐

  1. com.alibaba.druid.pool.DruidPooledConnection cannot be cast to oracle.jdbc.OracleConnection 异常解决办法

    java.lang.ClassCastException: com.alibaba.druid.pool.DruidPooledConnection cannot be cast to oracle. ...

  2. 信息熵 Information Entropy

    信息熵用于描述信源的不确定度, 即用数学语言描述概率与信息冗余度的关系. C. E. Shannon 在 1948 年发表的论文A Mathematical Theory of Communicati ...

  3. SNF快速开发平台2019-权限管理模型-平台服务(多平台\多组织\SAAS\多系统)

    1.1    不同组织机构 通俗的讲,就是一个集团公司,划分几个区域,每个区域都有什么分公司,每个分公司都有哪些部门一样,哪些部门又有那些子部门等. 当然也可以是外贸公司的全球性客户.合作伙伴的分布情 ...

  4. odoo开发笔记 -- 用户字段值,默认给当前登录用户

    场景描述: 在一些视图下,当系统用户创建某条记录的时候,需要给某个用户字段设置默认值,即:默认值为系统的当前登录用户,如何实现? 处理方式: 在定义模型的时候,给该字段赋值就可以: operator_ ...

  5. 解决 No IDEA annotations attached to the JDK 1.8和xml文件没有代码提示

    Android studio3.3 用着用着突然xml里没有代码联想了,忙着做其他的就没管,写xml的时候就硬写... 然后今天用着突然在class文件上方提示No IDEA annotations ...

  6. LeetCode 108. Convert Sorted Array to Binary Search Tree (将有序数组转换成BST)

    108. Convert Sorted Array to Binary Search Tree Given an array where elements are sorted in ascendin ...

  7. postman 测试Excel文件导入导出功能

    1.导入的测试方法 选择form-data,key值填写方法对应的参数,选择File,Value处上传文件即可. 2. 导出的测试方法 在导出文件的时候,响应结果是乱码,然后在测试的时候选择下载,下载 ...

  8. docker 启动mysql 闪退 无法启动问题

    docker 安装mysql [获取容器] docker pull mysql:5.6 [启动容器] docker run -p 3306:3306 --name mymysql -v $PWD/co ...

  9. C#中的ref和out与SQL中的output

    什么时候会需要使用ref和out 有时,我们会需要获取某个值在方法中的运行状态,根据定义的方法,我们仅仅能够获得一个返回值,但是,有时我们也许想获取多个值,通过返回值就不能返回这样的信息,我们可以通过 ...

  10. 【记录】【solr】whose UTF8 encoding is longer than the max length 32766

    java添加数据到solr报错 whose UTF8 encoding is longer than the max length 32766 原因是长度太长,string类型改成text_gener ...