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


注:java源码分析部分如无特殊说明均基于 java8 版本。

简介

Java的线程池是块硬骨头,对线程池的源码做深入研究不仅能提高对Java整个并发编程的理解,也能提高自己在面试中的表现,增加被录取的可能性。

本系列将分成很多个章节,本章作为线程池的第一章将对整个线程池体系做一个总览。

体系结构

上图列举了线程池中非常重要的接口和类:

(1)Executor,线程池顶级接口;

(2)ExecutorService,线程池次级接口,对Executor做了一些扩展,增加一些功能;

(3)ScheduledExecutorService,对ExecutorService做了一些扩展,增加一些定时任务相关的功能;

(4)AbstractExecutorService,抽象类,运用模板方法设计模式实现了一部分方法;

(5)ThreadPoolExecutor,普通线程池类,这也是我们通常所说的线程池,包含最基本的一些线程池操作相关的方法实现;

(6)ScheduledThreadPoolExecutor,定时任务线程池类,用于实现定时任务相关功能;

(7)ForkJoinPool,新型线程池类,java7中新增的线程池类,基于工作窃取理论实现,运用于大任务拆小任务、任务无限多的场景;

(8)Executors,线程池工具类,定义了一些快速实现线程池的方法(谨慎使用);

Executor

线程池顶级接口,只定义了一个执行无返回值任务的方法。

  1. public interface Executor {
  2. // 执行无返回值任务【本篇文章由公众号“彤哥读源码”原创】
  3. void execute(Runnable command);
  4. }

ExecutorService

线程池次级接口,对Executor做了一些扩展,主要增加了关闭线程池、执行有返回值任务、批量执行任务的方法。

  1. public interface ExecutorService extends Executor {
  2. // 关闭线程池,不再接受新任务,但已经提交的任务会执行完成
  3. void shutdown();
  4. // 立即关闭线程池,尝试停止正在运行的任务,未执行的任务将不再执行
  5. // 被迫停止及未执行的任务将以列表的形式返回
  6. List<Runnable> shutdownNow();
  7. // 检查线程池是否已关闭
  8. boolean isShutdown();
  9. // 检查线程池是否已终止,只有在shutdown()或shutdownNow()之后调用才有可能为true
  10. boolean isTerminated();
  11. // 在指定时间内线程池达到终止状态了才会返回true
  12. boolean awaitTermination(long timeout, TimeUnit unit)
  13. throws InterruptedException;
  14. // 执行有返回值的任务,任务的返回值为task.call()的结果
  15. <T> Future<T> submit(Callable<T> task);
  16. // 执行有返回值的任务,任务的返回值为这里传入的result
  17. // 当然只有当任务执行完成了调用get()时才会返回
  18. <T> Future<T> submit(Runnable task, T result);
  19. // 执行有返回值的任务,任务的返回值为null
  20. // 当然只有当任务执行完成了调用get()时才会返回
  21. Future<?> submit(Runnable task);
  22. // 批量执行任务,只有当这些任务都完成了这个方法才会返回
  23. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  24. throws InterruptedException;
  25. // 在指定时间内批量执行任务,未执行完成的任务将被取消
  26. // 这里的timeout是所有任务的总时间,不是单个任务的时间
  27. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
  28. long timeout, TimeUnit unit)
  29. throws InterruptedException;
  30. // 返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
  31. <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  32. throws InterruptedException, ExecutionException;
  33. // 在指定时间内如果有任务已完成,则返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
  34. <T> T invokeAny(Collection<? extends Callable<T>> tasks,
  35. long timeout, TimeUnit unit)
  36. throws InterruptedException, ExecutionException, TimeoutException;
  37. }

ScheduledExecutorService

对ExecutorService做了一些扩展,增加一些定时任务相关的功能,主要包含两大类:执行一次,重复多次执行。

  1. public interface ScheduledExecutorService extends ExecutorService {
  2. // 在指定延时后执行一次
  3. public ScheduledFuture<?> schedule(Runnable command,
  4. long delay, TimeUnit unit);
  5. // 在指定延时后执行一次
  6. public <V> ScheduledFuture<V> schedule(Callable<V> callable,
  7. long delay, TimeUnit unit);
  8. // 在指定延时后开始执行,并在之后以指定时间间隔重复执行(间隔不包含任务执行的时间)
  9. // 相当于之后的延时以任务开始计算【本篇文章由公众号“彤哥读源码”原创】
  10. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
  11. long initialDelay,
  12. long period,
  13. TimeUnit unit);
  14. // 在指定延时后开始执行,并在之后以指定延时重复执行(间隔包含任务执行的时间)
  15. // 相当于之后的延时以任务结束计算
  16. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
  17. long initialDelay,
  18. long delay,
  19. TimeUnit unit);
  20. }

AbstractExecutorService

抽象类,运用模板方法设计模式实现了一部分方法,主要为执行有返回值任务、批量执行任务的方法。

  1. public abstract class AbstractExecutorService implements ExecutorService {
  2. protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
  3. return new FutureTask<T>(runnable, value);
  4. }
  5. protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
  6. return new FutureTask<T>(callable);
  7. }
  8. public Future<?> submit(Runnable task) {
  9. if (task == null) throw new NullPointerException();
  10. RunnableFuture<Void> ftask = newTaskFor(task, null);
  11. execute(ftask);
  12. return ftask;
  13. }
  14. public <T> Future<T> submit(Runnable task, T result) {
  15. if (task == null) throw new NullPointerException();
  16. RunnableFuture<T> ftask = newTaskFor(task, result);
  17. execute(ftask);
  18. return ftask;
  19. }
  20. public <T> Future<T> submit(Callable<T> task) {
  21. if (task == null) throw new NullPointerException();
  22. RunnableFuture<T> ftask = newTaskFor(task);
  23. execute(ftask);
  24. return ftask;
  25. }
  26. public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  27. throws InterruptedException, ExecutionException {
  28. // 略...
  29. }
  30. public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
  31. long timeout, TimeUnit unit)
  32. throws InterruptedException, ExecutionException, TimeoutException {
  33. // 略...
  34. }
  35. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  36. throws InterruptedException {
  37. // 略...
  38. }
  39. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
  40. long timeout, TimeUnit unit)
  41. throws InterruptedException {
  42. // 略...
  43. }
  44. }

可以看到,这里的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. Photon Server 服务端编程

    Photon Server 和 Unity3D 数据交互: Photon Server 服务端编程 Unity3D 客户端编程 VS2017 之 MYSQL实体数据模 一:Photon Server的 ...

  2. CM & CDH 基本概念

    什么是 CDH Hadoop 是开源项目,所以很多公司在这个基础上进行商业化,不收费的 Hadoop 主要有三个: Apache,最原始的版本,所有发行版均基于这个版本进行 Cloudear,全称 C ...

  3. Erlcron分析学习

    介绍 Erlcron实现类似Linux下面的cron的计划任务. 源码下载地址:https://github.com/erlware/erlcron 原理 Erlcron进程监控树 ecrn_cron ...

  4. 【LeetCode】334#递增的三元子序列

    题目描述 给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列. 数学表达式如下: 如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1, 使得 ...

  5. TypeScript && React

    环境搭建 我们当然可以先用脚手架搭建React项目,然后手动配置成支持TypeScript的环境,虽然比较麻烦,但可以让你更清楚整个过程.这里比较麻烦,就不演示了,直接用命令配置好. npx crea ...

  6. (六十八)c#Winform自定义控件-DEMO整理

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  7. 64位linux编译32位程序

    昨天接到的任务,编译64位和32位两个版本的.so动态库给其他部门,我的ubuntu虚拟机是64位的,编译32位时遇到了问题: /usr/bin/ld: cannot find -lstdc++ 最后 ...

  8. spring boot 配置文件加密数据库用户名/密码

    这篇文章为大家分享spring boot的配置文件properties文件里面使用经过加密的数据库用户名+密码,因为在自己做过的项目中,有这样的需求,尤其是一些大公司,或者说上市公司,是不会把这些敏感 ...

  9. 第一次参与国际空间站ISS 的SSTV活动

    先来看看本次 ISS 的 SSTV活动公告 SSTV Event planned for Early August ARISS News Release                         ...

  10. [LeetCode] 由 “分形" 所想

    分形思想和递归思想有区别么? 一.简单例子 函数调用自己,简化了理解逻辑,但其他到处都是问题. #%% def listsum(numList): if len(numList) == 1: retu ...