目录

ThreadPoolExecutor 线程池概述

Executor 框架结构

线程池饱和策略

线程池工作流程图

工作队列排队策略


ThreadPoolExecutor 线程池概述

1、线程池是JDK1.5开始引入的,也叫Executor框架,或是Java并发框架

2、线程池相关的API在java.util.concurrent包中,常用到以下几个类和接口:

2.1、java.util.concurrent.Executor:一个只包含一个方法的接口,它的抽象含义是:用来执行一个Runnable任务的执行器

2.2、java.util.concurrent.ExecutorService:继承了Executor接口的接口,增加了很多对于任务和执行器的生命周期进行管理的方法

2.3、java.util.concurrent.ThreadFactory:一个生成新线程的接口。用户可以通过实现这个接口管理对线程池中生成线程的逻辑

2.4、java.util.concurrent.Executors:创建并返回其余各个实例的类,提供了很多不同的生成执行器的实用方法,比如基于线程池的执行器的实现。

2.5、java.util.concurrent.ThreadPoolExecutor:这个类维护了一个线程池,对于提交到此Executor中的任务,它不是创建新的线程而是使用池内的线程进行执行,对于数量巨大但执行时间很短的任务,可以显著地减少对于任务执行的开销。

Executor 框架结构

1、executor 结构主要包括任务、任务的执行和异步结果的计算。

2、任务:包括被执行任务需要实现的接口,如Runnable接口或Callable接口

3、任务的执行:包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口(ThreadPoolExecutor和ScheduledThreadPoolExecutor)

4、异步计算的结果:包括接口Future和实现Future接口的FutureTask类

使用线程池的好处:

1、降低资源消耗:可以重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。

3、提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控

线程池工作原理

1、当一个新的任务提交到线程池之后,线程池处理过程如下:

1.1、线程池判断核心线程池里的线程是否已满。未满时,则创建一个新的工作线程来执行任务。如果核心线程池里的线程已满,则执行第二步。

1.2、线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里等待执行。如果工作队列满了,则执行第三步。

1.3、线程池判断线程池(核心线程池外的线程池部分)的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

线程池饱和策略

1、常用的饱和策略如下(它们是 ThreadPoolExecutor 类中的内部类,可以直接调用):

Modifier and Type Class and Description
static class ThreadPoolExecutor.AbortPolicy 被拒绝的任务的处理程序,抛出一个 RejectedExecutionException
static class ThreadPoolExecutor.CallerRunsPolicy

一个被拒绝的任务的处理程序,直接在 execute方法的调用线程中运行被拒绝的任务,除非执行程序已经被关闭,否则这个任务被丢弃。

static class
ThreadPoolExecutor.DiscardOldestPolicy

被拒绝的任务的处理程序,丢弃最旧的未处理请求,然后重试 execute ,除非执行程序关闭,在这种情况下,任务被丢弃。

static class ThreadPoolExecutor.DiscardPolicy

被拒绝的任务的处理程序静默地丢弃被拒绝的任务。

AbortPolicy:Java 线程池默认的阻塞策略,即不执行此新任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute 需要 try catch,否则程序会直接退出。

DiscardPolicy:直接抛弃,新任务不执行,空方法

DiscardOldestPolicy:从队列里面抛弃head的一个任务,并再次execute 此task。

用户自定义拒绝策略(最常用):实现RejectedExecutionHandler,并自己定义策略模式

线程池工作流程图

1、以 ThreadPoolExecutor 为例展示线程池的工作流程

1、如果当前运行的线程少于corePoolSize(核心线程数),则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。

2、如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue(阻塞队列/任务队列)。

3、如果无法将任务加入BlockingQueue(队列已满),则在非corePool中创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。

4、如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并执行线程饱和策略,如:RejectedExecutionHandler.rejectedExecution()方法。

5、ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。

工作队列排队策略

1、已经说过当线程池中工作线程的总数量超过核心线程数量后,新加的任务就会放入工作队列中进行等待被执行

2、使用线程池就得创建ThreadPoolExecutor对象,通过ThreadPoolExecutor(线程池)类的构造方法创建时,就得指定工作队列,它是BlockingQueue<Runnable>接口,而实际开发中是指定此接口的具体实现类,常用的如下所示。

SynchronousQueue 直接提交

1、直接提交策略----意思是工作队列不保存任何任务被等待执行,而是直接提交给线程进行执行。

2、工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保存它们。

3、如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。

4、此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。

5、Executors的newCacheThreadPool()方法创建线程池,就是使用的此种排队策略

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

 LinkedBlockingQueue 无界队列

1、无界队列策略----无界指的是工作队列大小没有上限,可以添加无数个任务进行等待。

2、使用无界队列将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。于是创建的线程就不会超过 corePoolSize。因此,maximumPoolSize 的值也就无效了。所以一般让corePoolSize等于maximumPoolSize

3、当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列

4、Executors的newFixedThreadPool(int nThreads)方法创建线程池,就是使用的此种排队策略

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

ArrayBlockingQueue 有界队列

1、有界队列策略----意思是工作队列的大小是有限制的

2、优点是可以防止资源耗尽的情况发生,因为如果工作队列被无休止的添加任务也是很危险的

3、当工作队列排满后,就会执行线程饱和策略

// 构造线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2),new ThreadPoolExecutor.DiscardOldestPolicy());

4、如上核心线程为3个,每个线程的工作队列大小为2(即队列中最多有两个任务在等待执行),线程池最大线程数为4个

5、所以当工作线程数小于等于3时,直接新建线程执行任务;超过3时,任务会被添加进工作队列进行等待,3*2=6,当工作队列等待的任务数超过6个以后,则又会新建一个线程,此时整个线程池线程总数已经达到了4个,当还有任务进行添加时,此时将采取饱和策略。

ThreadPoolExecutor 线程池理论、饱和策略、工作队列排队策略相关推荐

  1. java线程池饱和策略_线程池的饱和策略-调用者执行 | 学步园

    java并发编程实践阅读笔记之线程池的饱和策略 使用java的任务管理框架的线程池执行任务时,线程池的任务等待队列被填满时,饱和策略开始发挥作用.ThreadPollExecutor的饱和策略通过se ...

  2. Java线程池系列--饱和策略(拒绝策略)的使用(有实例)

    原文网址:Java线程池系列--饱和策略(拒绝策略)的使用(有实例)_IT利刃出鞘的博客-CSDN博客 简介 本文用示例介绍Java线程池的饱和策略(拒绝策略). 概述 Java线程池的饱和策略如下: ...

  3. Java多线程学习总结(4)——ThreadPoolExecutor 线程池的拒绝策略学习总结

    前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...

  4. java corepoolsize_理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize

    我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为每一台机器允许的最大线程是一个有界值.也就是说ThreadPoolExecutor管理的线程数量是有界的.线程池就是用这些有 ...

  5. 线程池详解-队列、抛弃策略

    详细补充:<ThreadPoolExecutor 线程池源码解析以及相关理论> 无界队列 **newFixedThreadPool和newSingleThreadExecutor在默认情况 ...

  6. ThreadPoolExecutor线程池核心参数详解

    理解ThreadPoolExecutor线程池的corePoolSize.maximumPoolSize和poolSize 我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为 ...

  7. ThreadPoolExecutor线程池原理

    ThreadPoolExecutor线程池原理 线程池原理 1. 线程池的简单介绍 1.1 线程池是什么 1.2 线程池解决的核心问题是什么 2. 线程池的实现原理 2.1 线程池的执行流程 2.2 ...

  8. ThreadPoolExecutor 线程池的使用

    1.状态 状态 描述 RUNNING 允许提交新的任务处理 SHUTDOWN 不允许提交了,但是已提交的会继续执行完 STOP 不允许提交新的任务,也不会处理阻塞队列中未执行的任务,并设置正在执行的线 ...

  9. Java Executor源码解析(3)—ThreadPoolExecutor线程池execute核心方法源码【一万字】

    基于JDK1.8详细介绍了ThreadPoolExecutor线程池的execute方法源码! 上一篇文章中,我们介绍了:Java Executor源码解析(2)-ThreadPoolExecutor ...

  10. 手写一个线程池,带你学习ThreadPoolExecutor线程池实现原理

    摘要:从手写线程池开始,逐步的分析这些代码在Java的线程池中是如何实现的. 本文分享自华为云社区<手写线程池,对照学习ThreadPoolExecutor线程池实现原理!>,作者:小傅哥 ...

最新文章

  1. 风口再起:数据中心建设
  2. MySQL带IN关键字的子查询
  3. Angular 自定义结构化指令,如何传入多个输入参数
  4. java 写文件filewriter_使用FileWriter写文件
  5. 阿里云推PostgreSQL 10 高可用版
  6. php什么情况下使用静态属性,oop-做php项目什么时候该使用静态属性呢
  7. 人工智障学习笔记——机器学习(16)降维小结
  8. JDBC学习笔记(6)——获取自动生成的主键值处理Blob数据库事务处理
  9. 高德地图车道级导航适配OPPO Find N折叠屏手机
  10. 分享到:空间等各大网站 代码
  11. html5窗口播放插件,基于jQuery UI的模拟windows窗口插件
  12. js合并对象中有相同key值的_js 深比较和浅比较
  13. @JsonInclude、@JsonIgnore和@JsonFormat注解
  14. 如何实现TextBox与DropDownList的级联
  15. java希尔排序的实例,Java 插入排序之希尔排序的实例
  16. scrapy -selector
  17. 世界哲学日2600年西方哲学思想发展史谱系图和哲学50命题(公号回复“西方哲学”下载PDF彩标典藏版,欢迎转发、赞赏、支持科教)
  18. 关于计算机文献检索报告,计算机专业文献检索论文参考选题.doc
  19. 界面控件DotNetBar for WinForms使用教程:LayoutControl布局与通用代码设置(三)
  20. js关于鼠标划过事件

热门文章

  1. Word标题:自动编号
  2. 拓端tecdat|R语言大数据分析纽约市的311万条投诉统计可视化与时间序列分析
  3. dijkstra algorithm example
  4. 6、set_xlim、set_ylim、xticks、yticks、set_xlabels、set_ylabels 和 双坐标轴twin()
  5. 【Caffe实践】基于CNN的性别、年龄识别
  6. python求解括号匹配的相关问题
  7. linux 查看文件开头几行、末尾几行、中间几行
  8. java中struts2框架,概述Java的struts2框架
  9. git commit后,如何撤销commit
  10. Petri net是什么