Java有两个线程池类:ThreadPoolExecutor和ScheduledThreadPoolExecutor,继承AbstractExecutorService类,AbstractExecutorService类实现了ExecutorService接口。Java API提供了Executors工厂类来帮助创建各种线程池。

ThreadPoolExecutor 构造方法

ThreadPoolExecutor 的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

  1. corePoolSize:指定了线程池中的线程数量。
  2. maximumPoolSize:指定了线程池中的最大线程数量。
  3. keepAliveTime:当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多
    次时间内会被销毁。
  4. unit:keepAliveTime 的单位。
  5. workQueue:任务队列,被提交但尚未被执行的任务。
  6. threadFactory:线程工厂,用于创建线程,一般用默认的即可。
  7. handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。

ThreadPoolExecutor工作流程

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面
有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a、如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b、如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
c、如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要
创建非核心线程立刻运行这个任务;
d、如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池
会抛出异常 RejectExecutionException。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。

现代码实验下:

当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务。

public class Exam13_1 {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,new LinkedBlockingQueue<>(1));Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}};//任务1executor.submit(runnable);//任务2executor.submit(runnable);}
}

实验结果

从实验结果上可以看出,当执行任务1的线程(thread-1)执行完成之后,任务2并没有去复用thread-1而是新建线程(thread-2)去执行任务。

当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队(如果workQueue长度允许),等待空闲线程来执行。

public class Exam13_1 {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,new LinkedBlockingQueue<>(1));Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}};//任务1executor.submit(runnable);//任务2executor.submit(runnable);//任务3executor.submit(runnable);}
}

从实验结果上看,任务3会等待任务1执行完之后,有了空闲线程,才会执行。并没有新建线程执行任务3,这时maximumPoolSize=3这个参数不起作用

当队列里的任务数达到上限,并且池中正在运行的线程数小于maximumPoolSize,对于新加入的任务,新建线程。

public class Exam13_1 {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,new LinkedBlockingQueue<>(1));Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}};//任务1executor.submit(runnable);//任务2executor.submit(runnable);//任务3executor.submit(runnable);//任务4executor.submit(runnable);}
}


从实验结果上看,当任务4进入队列时发现队列的长度已经到了上限,所以无法进入队列排队,而此时正在运行的线程数(2)小于maximumPoolSize所以新建线程执行该任务。

当队列里的任务数达到上限,并且池中正在运行的线程数等于maximumPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略是抛异常)。

public class Exam13_1 {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,new LinkedBlockingQueue<>(1));Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}};//任务1executor.submit(runnable);//任务2executor.submit(runnable);//任务3executor.submit(runnable);//任务4executor.submit(runnable);//任务5executor.submit(runnable);}
}

实验结果分析:当任务5加入时,队列达到上限,池内运行的线程数达到最大,故执行默认的拒绝策略,抛异常。

转载于:https://www.cnblogs.com/aixw/p/10535434.html

ThreadPoolExecutor(上篇)相关推荐

  1. 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  2. ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别

    前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍ThreadPoolExecutor接受任务相关的两方面入参的意义和区别,池大小参数corePoolS ...

  3. ThreadPoolExecutor的应用和实现分析(中)—— 任务处理相关源码分析 线程利用(转)...

    前面一篇文章从Executors中的工厂方法入手,已经对ThreadPoolExecutor的构造和使用做了一些整理.而这篇文章,我们将接着前面的介绍,从源码实现上对ThreadPoolExecuto ...

  4. 深入理解线程池(ThreadPoolExecutor)——细致入微的讲源码。

    在上一篇博文<图解线程池原理>中,大体上介绍了线程池的工作原理. 这一篇从源码层面,细致剖析,文章会很长. 如果上篇文章内容没吸收,先看上篇,先易后难嘛. 本文源码是 java 1.8 版 ...

  5. 深入理解Java线程池:ThreadPoolExecutor

    线程池介绍 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题: 如果并发的请求数量非常多,但每个线 ...

  6. IOS视频编辑功能详解上篇-添加水印

    前言 用代码在简单视频编辑中,主要就是加美颜.水印(贴图).视频截取.视频拼接.音视频的处理,在美颜中,使用GPUImage即可实现多种滤镜.磨皮美颜的功能,并且可以脸部识别实时美颜等功能,这个有很多 ...

  7. TypeScript 从听说到入门(上篇)

    我为什么会这样念念又不忘 / 你用什么牌的箭刺穿我心脏 我也久经沙场 / 戎马生涯 / 依然 / 被一箭刺伤 --李荣浩<念念又不忘> 接下来我会分上.下两篇文章介绍 TypeScript ...

  8. 进程控制概念简介 多线程上篇(三)

    进程控制 进程的基本数据信息是操作系统控制管理进程的数据集合,这些信息就是用来控制进程的,此处我们说的进程控制就是进程的管理. 比如进程有状态,那么进程的创建.终止,状态的切换,这都不是进程自主进行的 ...

  9. ThreadPoolExecutor使用介绍

    private static ExecutorService exec = new ThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new Li ...

最新文章

  1. 一个NSObject对象占多少内存?
  2. Python金融大数据分析——第五章数据可视化(1)二维绘图
  3. 差分约束系统【模板】
  4. shell脚本传可选参数 getopts 和 getopt的方法
  5. 面试题24 二叉搜索树的后序遍历序列
  6. ajax datatype_Ajax的基本使用
  7. java 接口 白名单,SpringBoot HTTP接口跨域调用及白名单实现
  8. buffer sort Oracle,SQL执行计划中的BUFFER SORT是什么意思呢,请高手指点.
  9. 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_07.入门案例中使用的组件介绍
  10. 【C++】STL--常用算法
  11. 快压、360压缩、WinRAR关于打开快压通过超高压缩比压缩后的文件不兼容的问题
  12. Vista v12.0 Win32-ISO 1DVD(地震数据处理)
  13. 开源离线语音识别(SpeechRecognition)
  14. 最新版银灿如意烧AIBurn V2.0.0.1(支持IS903B/IS902E/IS916主控)
  15. 西方哲学史人物学说时间线
  16. 谈谈自由之刃游戏代理推广感受
  17. 概率论与数理统计 | (16) 方差分析与一元线性回归
  18. wordpress添加Auto Highslide图片灯箱效果
  19. 蓝桥杯 图形排版
  20. cad用键盘放大缩小_cad放大的命令多少(CAD的放大缩小快捷键是什么?)

热门文章

  1. python【力扣LeetCode算法题库】面试题59 - II- 队列的最大值
  2. nginx与mysql传输过程_某互联网企业技术发展史(四)配置nginx和mysql兼容Yii框架,上传网站并调试成功...
  3. java exec 调用vbs_通过java调用VBS,再用VBS执行Excel中的宏的例子 | 学步园
  4. js实现图片从左到右循环播放
  5. 提升网站竞争力从这三方面着手努力!
  6. c语言getitem函数,该借用和窃取的引用的Python C-API函数
  7. debain apt oracle jdk,debian安装oracle jdk
  8. linux系统怎么用wifi,【教程】Wii安装运行可用WIFI的Linux系统全攻略
  9. 如何两个电脑共享文件实现多人编辑_四款花钱都难买到的良心软件,每一款都是电脑必备...
  10. python黑客代码_[翻译]Python开发中的密码散列(Hashing)