1. 首页
  2. 死磕java容器

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

gchishenrujiexitixijiegou_1.png

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


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

简介

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

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

体系结构

gchishenrujiexitixijiegou_2.png

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

(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中的线程模型特别类似,都是基于工作窃取理论,特别适合于处理归并排序这种先分后合的场景。

gchishenrujiexitixijiegou_3.png

Executors

线程池工具类,定义了一系列快速实现线程池的方法——newXXX(),不过阿里手册是不建议使用这个类来新建线程池的,彤哥我并不这么认为,只要能掌握其源码,知道其利敝偶尔还是可以用的,后面我们再来说这个事。

彩蛋

无彩蛋不欢,今天的问题是定时任务线程池用的是哪种队列来实现的?

答:延时队列。定时任务线程池中并没有直接使用并发集合中的DelayQueue,而是自己又实现了一个DelayedWorkQueue,不过跟DelayQueue的实现原理是一样的。

延时队列使用什么数据结构来实现的呢?

答:堆(DelayQueue中使用的是优先级队列,而优先级队列使用的堆;DelayedWorkQueue直接使用的堆)。

关于延时队列、优先级队列和堆的相关内容点击下面的链接直达:

死磕 java集合之DelayQueue源码分析

死磕 java集合之PriorityQueue源码分析

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


作者:彤哥读源码

来源:https://www.cnblogs.com/tong-yuan/p/11674974.html


看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「方志朋」,公众号后台回复「666」 免费领取我精心整理的进阶资源教程
  4. JS中文网,Javascriptc中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,是给开发者用的 Hacker News,技术文章由为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。

    本文著作权归作者所有,如若转载,请注明出处

    转载请注明:文章转载自「 Java极客技术学习 」https://www.javajike.com

    标题:第39篇:死磕 java线程系列之线程池深入解析——体系结构

    链接:https://www.javajike.com/article/1957.html

« 第40篇:死磕 java线程系列之自己动手写一个线程池(续)
第38篇:死磕 java线程系列之线程池深入解析——构造方法»

相关推荐

QR code