Java线程池FutureTask实现原理详解
前言
线程池可以并发执行多个任务,有些时候,我们可能想要跟踪任务的执行结果,甚至在一定时间内,如果任务没有执行完成,我们可能还想要取消任务的执行,为了支持这一特性,ThreadPoolExecutor提供了 FutureTask 用于追踪任务的执行和取消。本篇介绍FutureTask的实现原理。
类视图
为了更好的理解FutureTask的实现原理,这里先提供几个重要接口和类的结构,如下图所示:
RunnableAdapter
ThreadPoolExecutor提供了submit接口用于提交任务,submit支持Runnable和Callable两种不同的接口,为了提供统一的对外接口,jdk在内部把Runnable给包装成了一个Callable,这一切是通过RunnableAdapter这个适配器来实现的。如下为RunnableAdapter的源码:
static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }
RunnableAdapter是Callable 的实现类,实现了call方法,而call方法仅仅是调用task.run(),然后return result,这样就能够确保在内部只需要统一处理Callable接口。
FutureTask实现原理
通过上一小节的了解,我们知道提交的Runnable任务在内部统一被转换为Callable任务。查看submit方法的返回值,为一个Future,实际上这个Futrue为FutureTask实例,通过此实例,调用get方法,可以阻塞当前线程,直到任务运行完毕,返回结果。
整个调用链条如下所示:
worker thread -> futureTask.run() -> callable.call() -> task.run()
如果提交的是Callable任务,则只有前面三个调用。
为了更好的展示整个流程,下面举例演示一遍执行流程。
1、 向线程池submit一个Callable任务(Runnable也会被转为Callable), 这时候Callable被传入一个FutureTask实例中,如下所示:
2、线程池使用一个线程,执行这个 FutureTask 任务,
线程执行任务过程比较简单,最终会调用Callable.call()或者是 Runnable.run()方法,然后得到一个结果,把结果存储在FutureTask实例的outcome属性中,同时把状态修改为NORMAL,表明任务已经执行完毕,可以获取结果了。
我们假设在执行 callable.call()
过程中有多个线程调用了 同个FutureTask实例的get方法,这时候,这些线程会被阻塞,存于一个栈中, 如下图所示:
线程1,2,3调用FutureTask.get
方法,由于任务未执行结束,这时候,三个线程都将被阻塞休眠,FutureTask中有一个栈,用于存放等待线程,栈顶指针为 FutureTask.waiters
引用,当任务执行完毕后,会迭代唤醒整个栈中的线程,这时候,各个线程都将被唤醒,并且可以顺利拿到任务的执行结果(执行结果存于 FutureTask.outcome)
。
FutureTask还支持任务的取消功能,这一切都是通过 FutureTask的state状态来协调多个线程的。
总结
FutureTask接口是一种实现机制,提供我们对任务的执行的跟踪以及控制,相比于线程池本身,比较简单,相信不难理解。
以上就是本文关于Java线程池FutureTask实现原理详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
相关文章
最新hadoop安装教程及hadoop的命令使用(亲测可用)
这篇文章主要介绍了最新hadoop安装教程(亲测可用),本文主要讲解了如何安装hadoop、使用hadoop的命令及遇到的问题解决,需要的朋友可以参考下2022-06-06Nacos后台频繁打印get changedGroupKeys:[]的问题及解决
这篇文章主要介绍了Nacos后台频繁打印get changedGroupKeys:[]的问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-01-01Java常用正则表达式验证类完整实例【邮箱、URL、IP、电话、身份证等】
这篇文章主要介绍了Java常用正则表达式验证类,结合完整实例形式分析了Java针对邮箱、网址URL、IP地址、电话、身份证等正则验证相关操作技巧,需要的朋友可以参考下2018-12-12Mybatis-Plus中的MetaObjectHandler组件的使用
MetaObjectHandler是Mybatis-Plus中一个实用组件,专门用于自动处理实体对象中的特定字段,如创建时间、更新时间、创建人和修改人等,该接口允许开发者在不修改业务代码的情况下,实现自动填充功能,极大地简化了代码的复杂性,感兴趣的可以了解一下2024-10-10
最新评论