(手机横屏看源码更方便)


注: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集合之DelayQueue源码分析

死磕 java集合之PriorityQueue源码分析

拜托,面试别再问我堆(排序)了!


欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一起畅游源码的海洋。

死磕 java线程系列之线程池深入解析——体系结构的更多相关文章

  1. 死磕 java同步系列之CyclicBarrier源码解析——有图有真相

    问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...

  2. 死磕 java同步系列之Phaser源码解析

    问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...

  3. 死磕 java同步系列之StampedLock源码解析

    问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...

  4. 死磕 java同步系列之Semaphore源码解析

    问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...

  5. 死磕 java同步系列之ReentrantReadWriteLock源码解析

    问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...

  6. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  7. 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...

  8. 死磕 java同步系列之CountDownLatch源码解析

  9. 死磕 java同步系列之zookeeper分布式锁

    问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...

  10. 死磕 java同步系列之redis分布式锁进化史

    问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...

随机推荐

  1. git连接远程分支

    今天在再用git连接到远程的dev分支的时候出现了下面的情况 $ git checkout -b dev origin/dev fatal: 'origin/dev' is not a commit ...

  2. abp(net core)+easyui+efcore实现仓储管理系统——菜单-下(十七)

    实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+easyui+efcore实现仓储管理系统——解决方案 ...

  3. ElasticSearch常见经典面试题

    1.为什么要使用Elasticsearch? ​ 因为在我们商城中的数据,将来会非常多,所以采用以往的模糊查询,模糊查询前置配置,会放弃索引,导致商品查询是全表扫面,在百万级别的数据库中,效率非常低下 ...

  4. springboot使用jdbcTemplate连接数据库

    springboot使用jdbcTemplate连接数据库 1.pom.xml: <?xml version="1.0" encoding="UTF-8" ...

  5. Vue 前端uni-app多环境配置部署服务器的问题

    目录 前端Vue 针对问题 package.json描述 多环境部署 查看源码获取解决方案 转载请标明出处: http://dujinyang.blog.csdn.net/ 本文出自:[奥特曼超人的博 ...

  6. PythonI/O进阶学习笔记_4.自定义序列类(序列基类继承关系/可切片对象/推导式)

    前言: 本文代码基于python3 Content: 1.python中的序列类分类 2. python序列中abc基类继承关系 3. 由list的extend等方法来看序列类的一些特定方法 4. l ...

  7. Java 截取字符串中指定数据及之后数据

    String resCallBackJson="12556{1{{{456858585{";        resCallBackJson = resCallBackJson.su ...

  8. LoadRunner11.安装破解

    Loadrunner安装及破解   一. 安装 1. 将ISO文件导入,打开光驱,运行“setup.exe” 2. 点击安装,部分机器会提示缺少“Microsoft Visual C++ 2005 S ...

  9. linux使用命令上传下载文件 -- lrzsz

    之前都是用Xftp工具在本地和linux系统之间上传下载文件,最近觉得麻烦,因为平时用Xshell连接,要传输文件的时候还要额外使用别的工具,下面是lrzsz的安装和简单的使用过程: 详细的使用可以s ...

  10. jenkins离线安装插件的方法(无法访问外网)

    最近项目要迁移环境,无法访问外网,因此jenkins的安装配置需要离线操作,在此记录 jenkins下载安装好之后,跳过插件的安装,新建用户进入jenkins界面,这些前置步骤我在之前的随笔里有写具体 ...