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


注: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. 计蒜客 ACM训练联盟周赛 第一场 从零开始的神棍之路 暴力dfs

    题目描述 ggwdwsbs最近被Zeratul和Kyurem拉入了日本麻将的坑.现在,ggwdwsbs有13张牌,Kyurem又打了一张,加起来有14张牌.ggwdwsbs想拜托你帮他判断一下,这14 ...

  2. java hdu A+B for Input-Output Practice (III)

    A+B for Input-Output Practice (III) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32 ...

  3. angular关于Bootstrap样式不起作用问题

    跟着慕课网的课程学习Angular,简直要被bootstrap的问题整死了,样式一直出不来,导航完全没有背景颜色.. 我在网上找了很多都试了,以下方法特别受用 1.把 "../node_mo ...

  4. centos7 kubernetes单机安装

    单机版的kubernetes 适合初学者,对kuber有个很好的入门. 因为centos系统内置了安装源.我们可以直接安装 1.yum install -y etco kubernetes 2.whe ...

  5. 041 模块5-jieba库的使用

    目录 一.jieba库基本介绍 1.1 jieba库概述 1.2 jieba库的安装 1.3 jieba分词的原理 二.jieba库使用说明 2.1 jieba分词的三种模式 2.2 jieba库常用 ...

  6. redis之pipeline使用

    redis之pipeline 我们要完成一个业务,可能会对redis做连续的多个操作,这有很多个步骤是需要依次连续执行的.这样的场景,网络传输的耗时将是限制redis处理量的主要瓶颈. 那么此时就可以 ...

  7. 使用maven的profile构建不同环境配置

    基本概念说明(resources.filter和profile): 1.profiles定义了各个环境的变量id 2.filters中定义了变量配置文件的地址,其中地址中的环境变量就是上面profil ...

  8. Windows10 系统更新之后找不到输入法

    是因为 , 系统更新之后 , 系统自带的输入法没有更新好 , 过个一两天,系统会自动修复. 简单解决办法是 , Ctrl+Alt+delete 打开任务管理器, 在进程中,按CPU大小排序,找到输入法 ...

  9. 加入百度地图遇到 framework not found BaiduMapAPI***

    新建一个文件夹,把需要的静态库和.h文件放到文件夹里面.就解决啦.虽然不知道为什么这样可以,但是可以使用啦~~~

  10. 一个vue练手的小项目

    编程路上的菜鸟一枚 : 最近接触了vue 然后写了一个练手的项目 使用vue-cli脚手架来搭建了的项目 技术: vue2  + vue-router  + ES6 + axios 框架有 mint- ...