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


注: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. JAVA - 一个for循环实现99乘法表

    public class Test03 {public static void main(String[] args) { int lie = 1; for (int hang = 1; hang&l ...

  2. 【转】Android CTS 测试

    http://blog.csdn.net/zxm317122667/article/details/8508013 Android-CTS 4.0.3测试基本配置 1. Download CTS CT ...

  3. 使用EF6简实现多租户的应用

    什么是多租户 网上有好多解释,有些上升到了架构设计,让你觉得似乎非常高深莫测,特别是目前流行的ABP架构中就有提到多租户(IMustHaveTenant),其实说的简单一点就是再每一张数据库的表中添加 ...

  4. 调用arcpy包批量进行矢量掩膜提取

    使用一个polygon矢量提取某个文件夹中所有的tif格式栅格数据 (要确保先安装好arcpy包) import arcpy arcpy.CheckOutExtension("spatial ...

  5. 集成学习方法Boosting和Bagging

    集成学习是通过构架并结合多个学习器来处理学习任务的一种思想, 目前主要分为两大类:Boosting和Bagging. 对于任意一种集成方法, 我们都希望学习出来的基分类器具有较高的准确性和多样性, 基 ...

  6. SRAM和DRAM的区别

    一.浅谈关于SRAM和DRAM的区别:https://www.cnblogs.com/nano94/p/4014082.html. 二.ROM.RAM.DRAM.SRAM和FLASH的区别,转自:ht ...

  7. Day4 总结

  8. 03 (OC)* UITableView优化

    一:cell注册和初始化 1:不注册cell 2:注册类 3:注册nib 4:storyboard 二:核心思想 1:UITableView的核心思想是:cell的重用机制.UITbleView只会创 ...

  9. 括号匹配(c语言实现)

    ⭐ 我的网站: www.mengyingjie.com ⭐ 1要求 编写程序检查该字符串的括号是否成对出现,而且不能交叉出现. 输入: 一个字符串,里边可能包含"()"." ...

  10. Django REST Framework之频率限制

    开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用 使用 自定义频率限制组件:utils/thottle.py class MyThrottle(BaseThrottle): ...