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() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}; //任务1
executor.submit(runnable); //任务2
executor.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() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}; //任务1
executor.submit(runnable); //任务2
executor.submit(runnable); //任务3
executor.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() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}; //任务1
executor.submit(runnable); //任务2
executor.submit(runnable); //任务3
executor.submit(runnable); //任务4
executor.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() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}; //任务1
executor.submit(runnable); //任务2
executor.submit(runnable); //任务3
executor.submit(runnable); //任务4
executor.submit(runnable); //任务5
executor.submit(runnable); }
}

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

ThreadPoolExecutor(上篇)的更多相关文章

  1. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  2. 系统间通信(3)——IO通信模型和JAVA实践 上篇

    来源:http://blog.csdn.net/yinwenjie 1.全文提要 系统间通信本来是一个很大的概念,我们首先重通信模型开始讲解.在理解了四种通信模型的工作特点和区别后,对于我们后文介绍搭 ...

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

    工作中多处接触到了ThreadPoolExecutor.趁着现在还算空,学习总结一下. 前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍ThreadP ...

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

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

  5. ThreadPoolExecutor(下篇)

    上篇写到了ThreadPoolExecutor构造方法前4个参数int corePoolSize.int maximumPoolSize,.long keepAliveTime.TimeUnit un ...

  6. 看看C# 6.0中那些语法糖都干了些什么(上篇)

    今天没事,就下了个vs2015 preview,前段时间园子里面也在热炒这些新的语法糖,这里我们就来看看到底都会生成些什么样的IL? 一:自动初始化属性 确实这个比之前的版本简化了一下,不过你肯定很好 ...

  7. 并发包的线程池第一篇--ThreadPoolExecutor执行逻辑

    学习这个很长时间了一直没有去做个总结,现在大致总结一下并发包的线程池. 首先,任何代码都是解决问题的,线程池解决什么问题? 如果我们不用线程池,每次需要跑一个线程的时候自己new一个,会导致几个问题: ...

  8. ThreadPoolExecutor源码学习(1)-- 主要思路

    ThreadPoolExecutor是JDK自带的并发包对于线程池的实现,从JDK1.5开始,直至我所阅读的1.6与1.7的并发包代码,从代码注释上看,均出自Doug Lea之手,从代码上看JDK1. ...

  9. ThreadPoolExecutor源码学习(2)-- 在thrift中的应用

    thrift作为一个从底到上除去业务逻辑代码,可以生成多种语言客户端以及服务器代码,涵盖了网络,IO,进程,线程管理的框架,着实庞大,不过它层次清晰,4层每层解决不同的问题,可以按需取用,相当方便. ...

随机推荐

  1. Sql Server两个数据库中有一张表的结构一样,怎么快速将一张表中的数据复制到另一个表中

    1,下面这句会把表2数据删除,然后把表1复制到表一,两表内容一样 SELECT * into 表2 FROM 表1 2,这句只追加,不删除表2的数据 insert into 表1 select * f ...

  2. Spring Eureka的使用入门

    Eureka调度服务: Gradle依赖包: 基础框架依赖配置核心代码: buildscript { repositories { mavenCentral() } dependencies {cla ...

  3. Mongodb服务的设置成window服务自启动

    服务安装bat:例子 cd D: D: cd "Program Files" cd MongoDB\Server\3.0\bin mongod -dbpath "F:\w ...

  4. Vuex 使用了 module 后的访问方法 ..

    如果 使用了  module 和 namespace state 数据:=>   this.$store.state.User.info  (user 是模块名字. info 是 state 里 ...

  5. php 页面压缩---

    网站优化中,页面压缩是很有效的一种方法,可以明显提升页面访问速度. 页面压缩也有很多的方法,有PHP自带的zlib的gzip压缩,还有清除html页面中不必要的字符,空格,注释,换行符等. 第一种打开 ...

  6. sharepoint_study_2

    描述:向SharePoint中批量添加用户 解决:原文地址:http://bbs.winos.cn/thread-89236-1-1.html 一般情况下,要想登录SharePoint server ...

  7. 【算法笔记】B1006 换个格式输出整数

    1006 换个格式输出整数 (15 分) 让我们用字母 B 来表示“百”.字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数 ...

  8. request.getRequestDispatcher()跳转+中文乱码

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...

  9. 把磁力下载站改为python系统

    已经一年半载没有写博客了,搞得上来不知道写些什么. 索马里影视下载  WWW.IBMID.COM  现在用的是CENTOS 7 系统, 经历了多次点技术变更.开源版本使用了django网站框架重写,之 ...

  10. Python-匿名函数(lambda),map()

    1. map() 描述 map() 会根据提供的函数对指定序列做映射. 第一个参数 function 以第二个参数序列中的每一个元素调用 function 函数,返回一个map对象. 语法 map() ...