在线程池出现之前,每次需要使用线程,都得创建一个线程。但是,在java的运行环境中,创建一个线程是非常耗费资源和时间的。是否可以把线程重复利用,减少线程的创建次数。基于此,java1.5中引入了java的线程池管理。试想如果让你来实现一个线程池的管理,你会怎么实现呢?
 
     下面详细分析java ThreadPoolExecutor类的线程池原理。
 
      线程池ThreadPoolExecutor的使用方,调用方式,是把任务提交到线程池,具体线程的创建和执行是透明的。ThreadPoolExecutor有两部分组成,一个是工作线程列表,另一个是等待队列。
      一个执行任务加入线程池,可简化成下面三种情况。
     1 当工作线程没有打到设定的最大线程数时,线程池将创建一个工作线程来执行任务。
     2 当工作线程已经达到设定的最大线程时,任务将放入等待队列。
     3 当工作线程已经达到设定的最大线程时,队列也排满后,加入的任务将被拒绝
 
     ThreadPoolExecutor 有四个构造方法
 
构造方法一:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
 
构造方法二:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
 
构造方法三:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
 
构造方法四:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
 
参数说明
     int corePoolSize: 线程池启动后,核心线程最大数;当线程数小于corePoolSize时,加入一个任务,就创建一个线程
     BlockingQueue<Runnable> workQueue: 当线程池的线程数达到corePoolSize后,新加入的任务将被加入到队列workQueue中,线程池中的线程执行完任务后,从workQueue中取任务执行
     int maximumPoolSize:当线程池的线程数已经达到corePoolSize之后,workQueue的长度也已经放满之后,线程数继续增加,直到达到maximumPoolSize。所以上面构造方法里要求 maximumPoolSize < corePoolSize 是不被允许的。
     long keepAliveTime:线程的空闲时间,TimeUnit unit是他的时间单位。当线程池中的线程数趋于corePoolSize和maximumPoolSize之间,线程的空闲时间达到keepAliveTime,将被回收。知道线程数降到corePoolSize数之后,就不在回收。如果用户调用方法allowsCoreThreadTimeOut()之后,如果线程空闲时间达到keepAliveTime,线程仍然能被回收
     ThreadFactory threadFactory:创建线程的工厂类
     RejectedExecutionHandler handler:是在线程池已经不能在创建线程了,workQueue队列也已经满了之后,在添加任务之后的拒绝策略。
 
   前面三个构造方法,实际上都会调用到最后一个构造方法。前面三个构造方法和最后一个方法的不同在部分参数没有开放出去,采用了默认值的形式。这是我们一贯的模式,一个主的构造方法,其他构造方法在他上面构建多样化,很多参数都可以采用默认方式,设计出符合各种场景的构造方法。
 
上面列的参数中,有两个参数可以采用默认值  ThreadFactory threadFactory,  RejectedExecutionHandler handler ;  构造方法一中,这两个参数都没传入,使用默认值;构造方法二中, RejectedExecutionHandler handler没传入,使用默认值; 构造方法三中 ThreadFactory threadFactory没传人,使用默认值。
 
这里先谈下线程池已经不在接收任务时,他的拒绝策略分析。有四种策略, CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy,AbortPolicy是线程池的默认拒绝策略。
 
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { } /**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 只要线程池没有关闭,添加任务的线程将负责任务的执行
if (!e.isShutdown()) {
r.run();
}
}
}
 
CallerRunsPolicy拒绝策略,线程池不能在接收任务后,只要线程池没有关闭,添加任务的线程将负责任务的执行
 
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { } /**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 拒绝后,抛出异常
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
AbortPolicy拒绝策略,线程池不能在接收任务后,在次添加,拒绝策略将抛出异常RejectedExecutionException
 
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { } /**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
 
DiscardPolicy拒绝策略,线程池不能在接收任务后,再次添加,什么都不做
 
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { } /**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
 
DiscardOldestPolicy拒绝策略,线程池不能在接收任务后,再次添加,将会从队列头部去掉一个任务,把新任务加入队列。
 
上面四个策略,根据具体场景来使用,也可以使用默认策略AbortPolicy。
 
其他分析接下文 《ThreadPoolExecutor源码分析二》 
 

ThreadPoolExecutor源码分析一的更多相关文章

  1. ThreadPoolExecutor源码分析(一)

    一.前言 闲来无事,博主有重新翻看了一下jdk1.8版的ThreadPoolExecutor源码,看后写此笔记,画个圈圈,做个记录,这段源码,我看过,到处一游,嘻嘻~~ 二.ThreadPoolExe ...

  2. Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析

    Java中使用线程池技术一般都是使用Executors这个工厂类,它提供了非常简单方法来创建各种类型的线程池: public static ExecutorService newFixedThread ...

  3. java多线程系列:ThreadPoolExecutor源码分析

    前言 这篇主要讲述ThreadPoolExecutor的源码分析,贯穿类的创建.任务的添加到线程池的关闭整个流程,让你知其然所以然.希望你可以通过本篇博文知道ThreadPoolExecutor是怎么 ...

  4. ThreadPoolExecutor源码分析-面试问烂了的Java线程池执行流程,如果要问你具体的执行细节,你还会吗?

    Java版本:8u261. 对于Java中的线程池,面试问的最多的就是线程池中各个参数的含义,又或者是线程池执行的流程,彷佛这已成为了固定的模式与套路.但是假如我是面试官,现在我想问一些更细致的问题, ...

  5. Python线程池ThreadPoolExecutor源码分析

    在学习concurrent库时遇到了一些问题,后来搞清楚了,这里记录一下 先看个例子: import time from concurrent.futures import ThreadPoolExe ...

  6. Java核心复习——线程池ThreadPoolExecutor源码分析

    一.线程池的介绍 线程池一种性能优化的重要手段.优化点在于创建线程和销毁线程会带来资源和时间上的消耗,而且线程池可以对线程进行管理,则可以减少这种损耗. 使用线程池的好处如下: 降低资源的消耗 提高响 ...

  7. 线程池ThreadPoolExecutor源码分析

    在阿里编程规约中关于线程池强制了两点,如下: [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程.说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源 ...

  8. ThreadPoolExecutor源码分析二

      接上文,这里继续分析源码 private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPA ...

  9. java.util.concurrent ThreadPoolExecutor源码分析

    实现的接口:Executor, ExecutorService 子类:ScheduledThreadPoolExecutor 这类为java线程池的管理和创建,其中封装好的线程池模型在Executor ...

随机推荐

  1. 【FFMEPG】windows下编译ffmpeg2.5——使用VS2013,ARMLINUX,ANDORID编译ffmpeg

    原文:http://blog.csdn.net/finewind/article/details/42784557 一.准备: 1. 本机环境: win7 64bit: 2. 安装MinGW到C:\M ...

  2. 【VS开发】malloc申请内存错误分析

    每个进程会有4G的虚拟地址空间, malloc得到的的地址都是虚拟地址, 并且当malloc的时候, 操作系统并不会将实际的内存分配给进程的, 所以malloc只会占用进程自身的虚拟地址空间.我以前也 ...

  3. OpenCV.用户选择

    1.Pdf.P153(书.P122) 2. // 来自:"Creating a video with OpenCV — OpenCV 2.4.13.7 documentation.html& ...

  4. 最新 完美世界java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.完美世界等10家互联网公司的校招Offer,因为某些自身原因最终选择了完美世界.6.7月主要是做系统复习.项目复盘.Leet ...

  5. mysql 启动出错

    错误:The server quit without updating PID file 看错误日志: Setting lower_case_table_names=2 because file sy ...

  6. win7 配置 用户/系统DSN (解决plsql odbc导入器 DSN 没有选项)

    (2013-05-07 15:07:29) 转载▼ 标签: it   老笔记本越来越卡,最近重新做了win7的系统 从sql server中导出的 excel文件 准备通过plsql倒入的oracle ...

  7. Creating mailbox file: 文件已存在

    原来linux下添加用户后,会在系统里自动加一个邮箱(系统邮箱),路径是:/var/spool/mail/用户名.可以直接用命令#rm -rf /var/spool/mail/用户名 这样就可以再次添 ...

  8. UI自动化的第一步(Python,pip,selenium,PyCharm安装配置)

    一,py安装 1.python下载,安装,环境配置 地址:https://www.runoob.com/python/python-install.html 注意:安装时,要勾选自动配置环境变量.这样 ...

  9. XSS跨站攻击靶场-通关笔记

    XSS攻击是Web攻击中最常见的攻击手法之一,XSS中文名跨站脚本攻击,该攻击是指攻击者在网页中嵌入恶意的客户端脚本,通常是使用JS编写的恶意代码,当正常用户访问被嵌入代码的页面时,恶意代码将会在用户 ...

  10. python入门pk小游戏

    import time import random flag = True while flag: player_win = 0 enemy_win = 0 for i in range(1, 4): ...