ThreadPoolExecutor 线程池理论、饱和策略、工作队列排队策略
目录
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
|
一个被拒绝的任务的处理程序,直接在 |
static class |
被拒绝的任务的处理程序,丢弃最旧的未处理请求,然后重试 |
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 线程池理论、饱和策略、工作队列排队策略相关推荐
- java线程池饱和策略_线程池的饱和策略-调用者执行 | 学步园
java并发编程实践阅读笔记之线程池的饱和策略 使用java的任务管理框架的线程池执行任务时,线程池的任务等待队列被填满时,饱和策略开始发挥作用.ThreadPollExecutor的饱和策略通过se ...
- Java线程池系列--饱和策略(拒绝策略)的使用(有实例)
原文网址:Java线程池系列--饱和策略(拒绝策略)的使用(有实例)_IT利刃出鞘的博客-CSDN博客 简介 本文用示例介绍Java线程池的饱和策略(拒绝策略). 概述 Java线程池的饱和策略如下: ...
- Java多线程学习总结(4)——ThreadPoolExecutor 线程池的拒绝策略学习总结
前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...
- java corepoolsize_理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize
我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为每一台机器允许的最大线程是一个有界值.也就是说ThreadPoolExecutor管理的线程数量是有界的.线程池就是用这些有 ...
- 线程池详解-队列、抛弃策略
详细补充:<ThreadPoolExecutor 线程池源码解析以及相关理论> 无界队列 **newFixedThreadPool和newSingleThreadExecutor在默认情况 ...
- ThreadPoolExecutor线程池核心参数详解
理解ThreadPoolExecutor线程池的corePoolSize.maximumPoolSize和poolSize 我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为 ...
- ThreadPoolExecutor线程池原理
ThreadPoolExecutor线程池原理 线程池原理 1. 线程池的简单介绍 1.1 线程池是什么 1.2 线程池解决的核心问题是什么 2. 线程池的实现原理 2.1 线程池的执行流程 2.2 ...
- ThreadPoolExecutor 线程池的使用
1.状态 状态 描述 RUNNING 允许提交新的任务处理 SHUTDOWN 不允许提交了,但是已提交的会继续执行完 STOP 不允许提交新的任务,也不会处理阻塞队列中未执行的任务,并设置正在执行的线 ...
- Java Executor源码解析(3)—ThreadPoolExecutor线程池execute核心方法源码【一万字】
基于JDK1.8详细介绍了ThreadPoolExecutor线程池的execute方法源码! 上一篇文章中,我们介绍了:Java Executor源码解析(2)-ThreadPoolExecutor ...
- 手写一个线程池,带你学习ThreadPoolExecutor线程池实现原理
摘要:从手写线程池开始,逐步的分析这些代码在Java的线程池中是如何实现的. 本文分享自华为云社区<手写线程池,对照学习ThreadPoolExecutor线程池实现原理!>,作者:小傅哥 ...
最新文章
- 风口再起:数据中心建设
- MySQL带IN关键字的子查询
- Angular 自定义结构化指令,如何传入多个输入参数
- java 写文件filewriter_使用FileWriter写文件
- 阿里云推PostgreSQL 10 高可用版
- php什么情况下使用静态属性,oop-做php项目什么时候该使用静态属性呢
- 人工智障学习笔记——机器学习(16)降维小结
- JDBC学习笔记(6)——获取自动生成的主键值处理Blob数据库事务处理
- 高德地图车道级导航适配OPPO Find N折叠屏手机
- 分享到:空间等各大网站 代码
- html5窗口播放插件,基于jQuery UI的模拟windows窗口插件
- js合并对象中有相同key值的_js 深比较和浅比较
- @JsonInclude、@JsonIgnore和@JsonFormat注解
- 如何实现TextBox与DropDownList的级联
- java希尔排序的实例,Java 插入排序之希尔排序的实例
- scrapy -selector
- 世界哲学日2600年西方哲学思想发展史谱系图和哲学50命题(公号回复“西方哲学”下载PDF彩标典藏版,欢迎转发、赞赏、支持科教)
- 关于计算机文献检索报告,计算机专业文献检索论文参考选题.doc
- 界面控件DotNetBar for WinForms使用教程:LayoutControl布局与通用代码设置(三)
- js关于鼠标划过事件
热门文章
- Word标题:自动编号
- 拓端tecdat|R语言大数据分析纽约市的311万条投诉统计可视化与时间序列分析
- dijkstra algorithm example
- 6、set_xlim、set_ylim、xticks、yticks、set_xlabels、set_ylabels 和 双坐标轴twin()
- 【Caffe实践】基于CNN的性别、年龄识别
- python求解括号匹配的相关问题
- linux 查看文件开头几行、末尾几行、中间几行
- java中struts2框架,概述Java的struts2框架
- git commit后,如何撤销commit
- Petri net是什么