Java多线程系列--“JUC线程池”02之 线程池原理(一)
概要
在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构。线程池的实现类是ThreadPoolExecutor类。本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理。内容包括:
ThreadPoolExecutor简介
ThreadPoolExecutor数据结构
线程池调度
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509941.html
ThreadPoolExecutor简介
ThreadPoolExecutor是线程池类。对于线程池,可以通俗的将它理解为"存放一定数量线程的一个线程集合。线程池允许若个线程同时允许,允许同时运行的线程数量就是线程池的容量;当添加的到线程池中的线程超过它的容量时,会有一部分线程阻塞等待。线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理。"
ThreadPoolExecutor数据结构
ThreadPoolExecutor的数据结构如下图所示:
各个数据在ThreadPoolExecutor.java中的定义如下:
// 阻塞队列。
private final BlockingQueue<Runnable> workQueue;
// 互斥锁
private final ReentrantLock mainLock = new ReentrantLock();
// 线程集合。一个Worker对应一个线程。
private final HashSet<Worker> workers = new HashSet<Worker>();
// “终止条件”,与“mainLock”绑定。
private final Condition termination = mainLock.newCondition();
// 线程池中线程数量曾经达到过的最大值。
private int largestPoolSize;
// 已完成任务数量
private long completedTaskCount;
// ThreadFactory对象,用于创建线程。
private volatile ThreadFactory threadFactory;
// 拒绝策略的处理句柄。
private volatile RejectedExecutionHandler handler;
// 保持线程存活时间。
private volatile long keepAliveTime; private volatile boolean allowCoreThreadTimeOut;
// 核心池大小
private volatile int corePoolSize;
// 最大池大小
private volatile int maximumPoolSize;
1. workers
workers是HashSet<Work>类型,即它是一个Worker集合。而一个Worker对应一个线程,也就是说线程池通过workers包含了"一个线程集合"。当Worker对应的线程池启动时,它会执行线程池中的任务;当执行完一个任务后,它会从线程池的阻塞队列中取出一个阻塞的任务来继续运行。
wokers的作用是,线程池通过它实现了"允许多个线程同时运行"。
2. workQueue
workQueue是BlockingQueue类型,即它是一个阻塞队列。当线程池中的线程数超过它的容量的时候,线程会进入阻塞队列进行阻塞等待。
通过workQueue,线程池实现了阻塞功能。
3. mainLock
mainLock是互斥锁,通过mainLock实现了对线程池的互斥访问。
4. corePoolSize和maximumPoolSize
corePoolSize是"核心池大小",maximumPoolSize是"最大池大小"。它们的作用是调整"线程池中实际运行的线程的数量"。
例如,当新任务提交给线程池时(通过execute方法)。
-- 如果此时,线程池中运行的线程数量< corePoolSize,则创建新线程来处理请求。
-- 如果此时,线程池中运行的线程数量> corePoolSize,但是却< maximumPoolSize;则仅当阻塞队列满时才创建新线程。
如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。在大多数情况下,核心池大小和最大池大小的值是在创建线程池设置的;但是,也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 进行动态更改。
5. poolSize
poolSize是当前线程池的实际大小,即线程池中任务的数量。
6. allowCoreThreadTimeOut和keepAliveTime
allowCoreThreadTimeOut表示是否允许"线程在空闲状态时,仍然能够存活";而keepAliveTime是当线程池处于空闲状态的时候,超过keepAliveTime时间之后,空闲的线程会被终止。
7. threadFactory
threadFactory是ThreadFactory对象。它是一个线程工厂类,"线程池通过ThreadFactory创建线程"。
8. handler
handler是RejectedExecutionHandler类型。它是"线程池拒绝策略"的句柄,也就是说"当某任务添加到线程池中,而线程池拒绝该任务时,线程池会通过handler进行相应的处理"。
综上所说,线程池通过workers来管理"线程集合",每个线程在启动后,会执行线程池中的任务;当一个任务执行完后,它会从线程池的阻塞队列中取出任务来继续运行。阻塞队列是管理线程池任务的队列,当添加到线程池中的任务超过线程池的容量时,该任务就会进入阻塞队列进行等待。
线程池调度
我们通过下面的图看看下面线程池中任务的调度策略,加深对线程池的理解。
图-01:
图-02:
说明:
在"图-01"中,线程池中有N个任务。"任务1", "任务2", "任务3"这3个任务在执行,而"任务3"到"任务N"在阻塞队列中等待。正在执行的任务,在workers集合中,workers集合包含3个Worker,每一个Worker对应一个Thread线程,Thread线程每次处理一个任务。
当workers集合中处理完某一个任务之后,会从阻塞队列中取出一个任务来继续执行,如图-02所示。图-02表示"任务1"处理完毕之后,线程池将"任务4"从阻塞队列中取出,放到workers中进行处理。
更多内容
1. Java多线程系列目录(共xx篇)
2. Java多线程系列--“JUC线程池”01之 线程池架构
Java多线程系列--“JUC线程池”02之 线程池原理(一)的更多相关文章
- Java多线程系列--“JUC原子类”02之 AtomicLong原子类
概要 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.本章以AtomicLong对基本类型的原子类进行介绍.内容包括:Atomic ...
- Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例
概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...
- Java多线程系列--“JUC原子类”04之 AtomicReference原子类
概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)Atomi ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
- Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类
概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...
- Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类
概要 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法 ...
- java 多线程系列---JUC原子类(三)之AtomicLongArray原子类
AtomicLongArray介绍和函数列表 在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操 ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
随机推荐
- c#读取webconfig
string Conn_str = ConfigurationManager.AppSettings["connectionString"].ToString();
- Async/Await FAQ
From time to time, I receive questions from developers which highlight either a need for more inform ...
- javascript自学002--DOM事件
事件流:元素接收事件的顺序 1.事件冒泡:事件由最具体的元素开始接收,逐级向上传递到document元素.即从里到外. 2.事件捕获:由外到里,先接收的是document然后逐级向内,最后才到具体的元 ...
- Intent组件的传参应用
Intent是要执行的操作的抽象描述 可以在startActivity.startService等方法中使用 最为常见的用法是在Activity之间传递数据 跳转并传值: Intent intent= ...
- SSH三大框架笔面试总结
Java工程师(程序员)面题 Struts,Spring,Hibernate三大框架 1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建Sess ...
- LDA和PLSA
看了<LDA数学八卦>和July的博客,里面涉及到好多公式推导...感觉好复杂,于是记录一些重点简洁的东西,忽略大批量铺垫,直接回答LDA和PLSA是区别: 在pLSA模型中,我们按照如下 ...
- xampp开启php-debug
[XDebug]zend_extension = "C:\xampp\php\ext\php_xdebug.dll";xdebug.profiler_append = 0;xdeb ...
- mono的远程调试
mono可以让.net程序运行在linux平台上.于是.net程序员有了mono之后就转身跨平台了.但开放环境往往还是在windows下,于是有了这样的需求,是否可以用windows下的源码来实机调试 ...
- .NET Core下使用gRpc公开服务(SSL/TLS)
一.前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多的教程中基本都是泛泛而谈,难以实际在实际环境中使用,而该篇 ...
- 【Python】调用WPS V9 API,实现PPT转PDF
WPS 的API,即COM,主要分为V8与V9两个版本,网上容易查到的例子,都是V8的. 现在官网上可以下载的,2013抢鲜版,就是V9的API. Python 调用COM 需要安装 Python f ...