死磕 java线程系列之线程池深入解析——体系结构

(手机横屏看源码更方便)
注:java源码分析部分如无特殊说明均基于 java8 版本。
简介
Java的线程池是块硬骨头,对线程池的源码做深入研究不仅能提高对Java整个并发编程的理解,也能提高自己在面试中的表现,增加被录取的可能性。
本系列将分成很多个章节,本章作为线程池的第一章将对整个线程池体系做一个总览。
体系结构

上图列举了线程池中非常重要的接口和类:
(1)Executor,线程池顶级接口;
(2)ExecutorService,线程池次级接口,对Executor做了一些扩展,增加一些功能;
(3)ScheduledExecutorService,对ExecutorService做了一些扩展,增加一些定时任务相关的功能;
(4)AbstractExecutorService,抽象类,运用模板方法设计模式实现了一部分方法;
(5)ThreadPoolExecutor,普通线程池类,这也是我们通常所说的线程池,包含最基本的一些线程池操作相关的方法实现;
(6)ScheduledThreadPoolExecutor,定时任务线程池类,用于实现定时任务相关功能;
(7)ForkJoinPool,新型线程池类,java7中新增的线程池类,基于工作窃取理论实现,运用于大任务拆小任务、任务无限多的场景;
(8)Executors,线程池工具类,定义了一些快速实现线程池的方法(谨慎使用);
Executor
线程池顶级接口,只定义了一个执行无返回值任务的方法。
public interface Executor {
// 执行无返回值任务【本篇文章由公众号“彤哥读源码”原创】
void execute(Runnable command);
}
ExecutorService
线程池次级接口,对Executor做了一些扩展,主要增加了关闭线程池、执行有返回值任务、批量执行任务的方法。
public interface ExecutorService extends Executor {
// 关闭线程池,不再接受新任务,但已经提交的任务会执行完成
void shutdown();
// 立即关闭线程池,尝试停止正在运行的任务,未执行的任务将不再执行
// 被迫停止及未执行的任务将以列表的形式返回
List<Runnable> shutdownNow();
// 检查线程池是否已关闭
boolean isShutdown();
// 检查线程池是否已终止,只有在shutdown()或shutdownNow()之后调用才有可能为true
boolean isTerminated();
// 在指定时间内线程池达到终止状态了才会返回true
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// 执行有返回值的任务,任务的返回值为task.call()的结果
<T> Future<T> submit(Callable<T> task);
// 执行有返回值的任务,任务的返回值为这里传入的result
// 当然只有当任务执行完成了调用get()时才会返回
<T> Future<T> submit(Runnable task, T result);
// 执行有返回值的任务,任务的返回值为null
// 当然只有当任务执行完成了调用get()时才会返回
Future<?> submit(Runnable task);
// 批量执行任务,只有当这些任务都完成了这个方法才会返回
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
// 在指定时间内批量执行任务,未执行完成的任务将被取消
// 这里的timeout是所有任务的总时间,不是单个任务的时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
// 返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
// 在指定时间内如果有任务已完成,则返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ScheduledExecutorService
对ExecutorService做了一些扩展,增加一些定时任务相关的功能,主要包含两大类:执行一次,重复多次执行。
public interface ScheduledExecutorService extends ExecutorService {
// 在指定延时后执行一次
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
// 在指定延时后执行一次
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
// 在指定延时后开始执行,并在之后以指定时间间隔重复执行(间隔不包含任务执行的时间)
// 相当于之后的延时以任务开始计算【本篇文章由公众号“彤哥读源码”原创】
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
// 在指定延时后开始执行,并在之后以指定延时重复执行(间隔包含任务执行的时间)
// 相当于之后的延时以任务结束计算
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
}
AbstractExecutorService
抽象类,运用模板方法设计模式实现了一部分方法,主要为执行有返回值任务、批量执行任务的方法。
public abstract class AbstractExecutorService implements ExecutorService {
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
// 略...
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
// 略...
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
// 略...
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
// 略...
}
}
可以看到,这里的submit()方法对传入的任务都包装成了FutureTask来进行处理,这是什么东西呢?欢迎关注后面的章节。
ThreadPoolExecutor
普通线程池类,这也是我们通常所说的线程池,包含最基本的一些线程池操作相关的方法实现。
线程池的主要实现逻辑都在这里面,比如线程的创建、任务的处理、拒绝策略等,我们后面单独分析这个类。
ScheduledThreadPoolExecutor
定时任务线程池类,用于实现定时任务相关功能,将任务包装成定时任务,并按照定时策略来执行,我们后面单独分析这个类。
问题:你知道定时任务线程池类使用的是什么队列吗?
ForkJoinPool
新型线程池类,java7中新增的线程池类,这个线程池与Go中的线程模型特别类似,都是基于工作窃取理论,特别适合于处理归并排序这种先分后合的场景。

Executors
线程池工具类,定义了一系列快速实现线程池的方法——newXXX(),不过阿里手册是不建议使用这个类来新建线程池的,彤哥我并不这么认为,只要能掌握其源码,知道其利敝偶尔还是可以用的,后面我们再来说这个事。
彩蛋
无彩蛋不欢,今天的问题是定时任务线程池用的是哪种队列来实现的?
答:延时队列。定时任务线程池中并没有直接使用并发集合中的DelayQueue,而是自己又实现了一个DelayedWorkQueue,不过跟DelayQueue的实现原理是一样的。
延时队列使用什么数据结构来实现的呢?
答:堆(DelayQueue中使用的是优先级队列,而优先级队列使用的堆;DelayedWorkQueue直接使用的堆)。
关于延时队列、优先级队列和堆的相关内容点击下面的链接直达:
欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一起畅游源码的海洋。

死磕 java线程系列之线程池深入解析——体系结构的更多相关文章
- 死磕 java同步系列之CyclicBarrier源码解析——有图有真相
问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...
- 死磕 java同步系列之Phaser源码解析
问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...
- 死磕 java同步系列之StampedLock源码解析
问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...
- 死磕 java同步系列之Semaphore源码解析
问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁
问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...
- 死磕 java同步系列之CountDownLatch源码解析
- 死磕 java同步系列之zookeeper分布式锁
问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...
- 死磕 java同步系列之redis分布式锁进化史
问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...
随机推荐
- CH4301 Can you answer on these queries III 题解
给定长度为N的数列A,以及M条指令 (N≤500000, M≤100000),每条指令可能是以下两种之一: "2 x y",把 A[x] 改成 y. "1 x y&quo ...
- centos 6.5 系统故障分析实验
系统故障分析实验 日志文件分析 日志的功能 用于记录系统.程序运行中发生的各种事件 通过阅读日志,有助于诊断和解决系统故障 日志文件的分类 内核及系统日志 由系统服务syslog统一进行管理,日志格式 ...
- Java日志框架总结
1. 前言 从写代码开始,就陆陆续续接触到了许多日志框架,较常用的属于LOG4J,LogBack等.每次自己写项目时,就copy前人的代码或网上的demo.配置log4j.properties或者lo ...
- Spring Boot2 系列教程(三)理解 Spring Boot 项目中的 parent
前面和大伙聊了 Spring Boot 项目的三种创建方式,这三种创建方式,无论是哪一种,创建成功后,pom.xml 坐标文件中都有如下一段引用: <parent> <groupId ...
- HashMap面试必问的数据结构相关知识
如果在看这篇文章时,对HashMap的结构还不是很了解,建议你参考前段时间写的<刨死你系列——HashMap剖析(基于jdk1.8)>,可能会对下面的提及到知识点有些帮助. 1:HashM ...
- Linux下编译提示arm-none-linux-gnueabi-gcc: command not found
自己的Linux系统中已经正确安装了交叉编译器arm-2009q3,路径设置正常. 但是在使用arm-none-linux-gnueabi-gcc编译时提示 arm-none-linux-gnuea ...
- [1]尝试用Unity3d制作一个王者荣耀(持续更新)->选择英雄-(上)
如果已经看过本章节:目录传送门:这是目录鸭~ 1.场景搭建: 首先我们去AssetStore逛淘宝~~~ 我淘到的是这个资源,其他好看的场景(消耗不高的都行). 然后我们导入了这个资源后,把资源根文件 ...
- Windows10 系统更新之后找不到输入法
是因为 , 系统更新之后 , 系统自带的输入法没有更新好 , 过个一两天,系统会自动修复. 简单解决办法是 , Ctrl+Alt+delete 打开任务管理器, 在进程中,按CPU大小排序,找到输入法 ...
- 在JSP页面用EL表达式获取数据
<h4>获取域对象中的值</h4><% request.setAttribute("name", "射雕英雄传"); ...
- Net基础篇_学习笔记_第十一天_面向对象(面向过程与面向对象的区别/类的概念)
1.面向过程-----> 面向对象 面向过程:面向的是完成这件事儿的过程,强调的是完成这件事儿的动作. 把大象塞进冰箱里1.打开冰箱门2.把大象塞进去,亲下大象的屁股3.关闭冰箱门 孙全 瘦小 ...