前言

线程池可以并发执行多个任务,有些时候,我们可能想要跟踪任务的执行结果,甚至在一定时间内,如果任务没有执行完成,我们可能还想要取消任务的执行,为了支持这一特性,ThreadPoolExecutor提供了 FutureTask 用于追踪任务的执行和取消。本篇介绍FutureTask的实现原理。

类视图

为了更好的理解FutureTask的实现原理,这里先提供几个重要接口和类的结构,如下图所示:

RunnableAdapter

ThreadPoolExecutor提供了submit接口用于提交任务,submit支持Runnable和Callable两种不同的接口,为了提供统一的对外接口,jdk在内部把Runnable给包装成了一个Callable,这一切是通过RunnableAdapter这个适配器来实现的。如下为RunnableAdapter的源码:

static final class RunnableAdapter implements Callable {

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实现原理详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

future java 原理_Java线程池FutureTask实现原理详解相关推荐

  1. java set和get原理_Java线程池的实现原理和使用

    为什么用线程池 在我们进行开发的时候,为了充分利用系统资源,我们通常会进行多线程开发,实现起来非常简单,需要使用线程的时候就去创建一个线程(继承Thread类.实现Runnable接口.使用Calla ...

  2. Java常用四大线程池用法以及ThreadPoolExecutor详解

    2019独角兽企业重金招聘Python工程师标准>>> 为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率 2.线程并发数量过多 ...

  3. java 重启线程_java 可重启线程及线程池类的设计(详解)

    了解JAVA多线程编程的人都知道,要产生一个线程有两种方法,一是类直接继承Thread类并实现其run()方法:二是类实现Runnable接口并实现其run()方法,然后新建一个以该类为构造方法参数的 ...

  4. Java线程池七个参数详解

    java多线程开发时,常常用到线程池技术,这篇文章是对创建java线程池时的七个参数的详细解释. 从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize.maximumPoolS ...

  5. java线程池概念_Java 线程池概念、原理、简单实现

    线程池的思想概述 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结東了,这样频繁创建线程就会大大降低系 ...

  6. java 工作池_Java线程池的工作原理,好处和注意事项

    线程池的工作原理 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列(阻塞队列) . 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列 ...

  7. java线程池的工作原理_JAVA线程池原理详解一

    线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...

  8. java异常_Java线程池「异常处理」正确姿势:有病就得治

    假设我们有一个线程池,由于程序需要,我们向该线程池中提交了好多好多任务,但是 这些任务都没有对异常进行try catch处理,并且运行的时候都抛出了异常 .这会对线程池的运行带来什么影响? 正确答案是 ...

  9. java并发编程——线程池的工作原理与源码解读

    2019独角兽企业重金招聘Python工程师标准>>> 线程池的简单介绍 基于多核CPU的发展,使得多线程开发日趋流行.然而线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以 ...

最新文章

  1. 推荐给c++学习者的经典
  2. skynet-源码分析1:目录下的文件整理
  3. 2019 Java 开发者跳槽指南.pdf (吐血整理)
  4. Soul回应下架整改:将严格审核相关功能和内容
  5. 继Nat Friedman离开Github之后,Xamarin联合创始人离开微软
  6. 何时、何地应用何种窗函数?
  7. 前端把cookie写在父域里_单点登录的三种实现方式
  8. 不存在理想中的那种单元测试
  9. 浙大计算机科学与技术专业课表,浙江大学 计算机科学与技术专业课程设置
  10. 一文看懂,Scrapy 底层逻辑是如此的简单
  11. 简述XSS攻击及其防范措施
  12. 一元二次方程求根c语言编码,一元二次方程求解程序完整代码
  13. redis主从、哨兵、集群
  14. SPP (Spatial Pyramid Pooling)
  15. c语言任伟,任 伟
  16. Java课后题第十二章:12.18(添加包语句)
  17. 神经网络方法研究及应用,神经网络基础与应用
  18. 风控中所涉及的重要指标全解析
  19. rstudio拉格朗日插值法_拉格朗日插值法函数使用问题
  20. 计算机无法播放视频,电脑自带播放器无法播放视频怎么办

热门文章

  1. VTK修炼之道29:图像统计_彩色直方图计算
  2. cannot resolve symbol ‘R‘ 程序包R不存在
  3. badboy测试工具下载
  4. mac os 和 ubuntu 上测试工具check-0.9.10的安装
  5. Netty自定义协议
  6. C++STL理论基础
  7. C语言再学习 -- 存储类、链接
  8. Linux内核学习的一些国外网站
  9. hdu1597(二分)
  10. 用隐马尔可夫模型(HMM)做命名实体识别——NER系列(二)