首页 > 编程语言 >【源码分析】FutureTask超详细的源码分析

【源码分析】FutureTask超详细的源码分析

时间:2024-11-11 09:45:45浏览次数:7  
标签:分析 get 任务 源码 线程 FutureTask 执行 方法

介绍
FutureTask是一个可取消的异步计算。
    1.通过get方法异步的获取任务执行结果
    2.通过cancel方法来尝试取消正在执行的任务
    3.通过get方法来捕获线程内部执行任务时抛出的异常

    那么,大家是否知道上述这些方法的底层呢,为什么get方法能获取到任务的结果?cancel方法是怎么样取消任务的?通过get方法为什么能捕获到内部线程执行任务时抛出的异常,是怎么样实现的?

接下来让我们带着问题在源码中寻找答案。

            !!!嘎嘎详细,看完后保证你会豁然开朗!!!

1.FutureTask的类图

首先,我们看一下FutureTask的类图
在这里插入图片描述
FutureTask实现了RunnableFuture接口。
    Runnable接口:这意味着它既可以作为一个任务提交给线程执行
    Future接口:这意味着它可以用来获取异步计算的结果

2.源码解析

2.1 构造函数

我们先从构造函数入手
在这里插入图片描述
FutureTask支持两种传参
    1.第一种传递一个Callable,Callable接口定义了一个可以返回值或抛出异常的操作。
    2.第二种传递了一个Runnable和result,进入到底层可以看到,最终Runnable和result都被封装成了Callable。如下:
在这里插入图片描述
    经过构造函数后,我们的任务已经被保存到成员变量中了,并且FutureTask的状态被初始化为NEW(新建状态)。

2.2 内部的run方法

我们在构建了一个FutureTask后,第二步就是将它扔到线程池中去执行了。

上述的类图可以看到FutureTask继承了Runnable接口,那么当FutureTask在线程中执行时,那就是执行它的run方法了。接下来让我们就进入到它的run方法中。
在这里插入图片描述
    标签1:这里执行了我们的任务,并返回了结果
    标签2:这里的set方法,传参是result结果,那这里面一定就是处理返回结果的地方了。(后面会详细讲解这个方法)
    标签3:执行任务中出现的异常被setException方法给处理了,我们知道FutureTask的get方法是能够捕获并抛出内部线程执行中的异常的,那么,关于get方法捕获内部线程抛出的异常的奥秘,就一定在这个setException方法里面了。

进入到set方法和setException方法中:
在这里插入图片描述
    这两方法的逻辑相同,都是先将我们任务的状态由新建改成了完成中
    并且将result或者异常对象都放到了成员变量outcome(这个名字一听就是到时候会返回的东西了)
    
    这里只是将异常放到了outcome变量中啊,并没有抛出去。
    没错,这里只是暂存到outcome中呢,那我这里就先给大家解开疑惑。(后面还会讲解report方法的)
在这里插入图片描述
    这里能看到,在最后获取结果的逻辑中,我们的任务执行中的异常被封装到了ExecutionException中并抛了出去,因此用户可以通过get方法中抛出的ExecutionException异常来拿到内部线程执行任务中抛出的异常

2.3 get方法

当我们执行了任务后,会通过FutureTask的get方法来获取返回结果
我们进入到get方法中,看看get方法做了什么操作。

这里首先介绍一下任务的状态(方便后续阅读),任务状态一共有7种。
在这里插入图片描述
NEW: 表示任务刚被创建,还未开始执行。
COMPLETING: 任务已经执行完成,但结果或异常还未设置到相应的字段中。
NORMAL: 任务正常完成,并且结果已经成功设置。
EXCEPTIONAL: 任务执行过程中抛出了异常,异常已经设置到相应字段。
CANCELLED: 任务被取消。
INTERRUPTING: 任务正在被中断处理过程中。
INTERRUPTED: 任务已经被中断完成。

进入到get方法中
在这里插入图片描述
    方法1:阻塞等待获取结果
    方法2:非阻塞,超时了会抛异常

2.4 awaitDone方法

在get方法中,可以看到,当任务的状态小于COMPLETING时(也就是任务处于新建状态时),都会进入到awaitDone方法中。
在这里插入图片描述
    awaitDone方法内部有一个for循环
我们逐行解析内部的逻辑

标签1
在这里插入图片描述
    这里会判断线程是否中断(这个线程不是执行任务的线程,执行任务的线程会保存在成员变量runner中。这里的线程是执行FutureTask的方法的线程),当检测到线程被中断就会抛出异常。

标签2
在这里插入图片描述

    判断了线程的状态是否已完成,完成了就会返回状态值

标签3
在这里插入图片描述
    如果任务处于完成中的状态,就暂时释放当前cpu的资源
为什么要释放呢?
    因为你的任务已完成,但是可能还需要等1秒中才出结果,那么你就不要一直在for循环中循环查询结果浪费cpu资源了,请暂时把cpu资源给更重要的任务吧,等下次cpu时间片资源分配给你的时候,你再返回结果也不迟。

标签4
在这里插入图片描述
    节点如果为空,就创建一个新的节点,为后续的入队做准备。

标签5
在这里插入图片描述
    判断节点入队了没,发现节点没入队,就给标签4创建的节点入队(入队操作其实就是将这个节点给放到链表的头位置)

标签6
在这里插入图片描述
get方法设置了超时时间。
    已超时:直接返回状态值
    未超时:挂起到超时的时间点(中途如果任务执行结束了,就请唤醒我,就会返回状态值了。不然等到我挂起到超时时间点了,会自动唤醒,也会返回状态值)

标签7
在这里插入图片描述
    直接挂起当前线程了,免得浪费cpu资源,等结果出来了在唤醒我吧,不然我就一直挂起了(这里就是get方法就会一直阻塞的原因

至此,awaitDone方法的逻辑就走完了。

2.5 cancel方法

在这里先介绍一下cancel方法
在这里插入图片描述
可以看到,在cancel方法中中断了任务执行的线程。
    注意:这里只是给线程打上了一个中断的标记,具体任务执行是否结束,需要大家自己在任务里面添加响应中断的逻辑。(如果不添加任何判断中断的逻辑,那么cancel方法其实是没有任何效果的)

    最后会执行finishCompletion方法:这个方法会将队列中的节点挂起的线程全部唤醒(别挂起了,快检查一下自己的任务执行完了没!!!),后续会细讲。

2.6 set方法

在上述awaitDone方法的标签6和标签7中,我们看到线程被挂起了,那么什么时候会被唤醒呢?

    在上一步的cancel方法中,就会唤醒,奥秘就在finishCompletion方法中。
    但是,除了cancel方法,还有一个关键的方法会执行唤醒操作,这个地方就是正常执行完并出结果的方法了。
在这里插入图片描述
这个run方法在上面已经介绍过了,接下来我们进入到这个set方法中详细看一下。
在这里插入图片描述
可以看到,这里也执行了finishCompletion方法!!!

2.7 finishCompletion方法

让我们进入到finishCompletion方法中一探究竟。
在这里插入图片描述
    这里可以看到,将等待队列中的节点,通过for循环一个一个拿到,并将对应的线程唤醒了(别挂起了!!!结果出来了!!!)。
至此就和上面的awaitDone方法的标签6和标签7对应上了。

2.8 report方法

最后进入到report方法中了,来看一下最后的一步。
在这里插入图片描述
在这里插入图片描述
    正常返回:将结果直接返回
    被取消:抛出一个取消异常
    异常返回:将异常对象封装到ExecutionException异常里面抛出

至此,我们的结果也就返回了。

2.9 回顾

最后让我们来回顾最开始的疑问:

1.为什么get方法能获取到任务的结果?

在FutureTask的awaitDone方法中会循环获取任务的执行状态,当发现任务的状态已完成时,就会将结果进行处理后返回。


2.cancel方法是怎么样尝试取消任务的?

在cancel时,会将执行任务的线程打上中断的标记,这里需要用户在任务中添加响应中断的逻辑,否则执行cancel方法时没有任务效果的。


3.通过get方法为什么能捕获到内部线程执行任务时抛出的异常,是怎么样实现的?

在FutureTask的run方法中,执行的时候会通过try catch捕获到内部线程执行的异常,并将异常信息赋值到成员变量outcome中,最后将outcome强转成异常封装到ExecutionException中返回。

标签:分析,get,任务,源码,线程,FutureTask,执行,方法
From: https://blog.csdn.net/qq_57102164/article/details/143528608

相关文章

  • SSM航空票务管理系统-计算机设计毕业源码77189
    目录1绪论1.1选题背景与意义1.2国内外研究现状1.3研究的主要内容1.4论文结构与章节安排2系统分析2.1.1技术可行性分析2.1.2 经济可行性分析2.1.3法律可行性分析2.2系统流程分析2.2.1数据新增流程2.2.2 数据删除流程2.3 系统功能分析2.3.......
  • asp.net程序设计1945消防宣传网站(源码)
    项目包含:源码、参考论文、讲解视频、说明文档请查看博主个人简介开发环境开发工具:VisualStudio2010或以上版本数据库:SQLServer2005或以上版本开发语言:c#操作系统:windows7或以上浏览器:GoogleChrome(推荐)、Edge、360浏览器消防工作是一项知识性、科学性、社会......
  • java计算机毕业设计大学生创新实践成果管理与分析推荐系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、研究背景在现代高等教育体系中,大学生创新实践活动日益受到重视,其是培养学生创新能力、实践能力和综合素质的关键途径。随着高校教育的不断发展,大学生参与......
  • Python数据分析-超市销售数据分析和可视化
    一、研究背景在现代零售业中,超市作为顾客日常消费的重要场所,承担着提供各种商品和服务的角色。随着数字化和电子商务的快速发展,消费者需求日益多样化,零售业竞争愈发激烈,了解消费者的购物行为、偏好、和消费模式成为超市经营和管理的关键因素之一。利用数据分析方法对超市销售......
  • 大数据项目-基于python实现的人才招聘数据分析与可视化平台
    《[含文档+PPT+源码等]精品基于python实现的人才招聘数据分析与可视化平台》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、包运行成功以及课程答疑与微信售后交流群、送查重系统不限次数免费查重等福利!数据库管理工具:phpstudy/Navicat或者phpstudy/sqlyog后台管......
  • django违法犯罪防范科普平台系统-计算机毕业设计源码84527
    摘 要本文介绍了一个基于Django的违法犯罪防范科普平台的设计与实现。随着社会的进步和科技的发展,违法犯罪活动呈现多样化和复杂化的趋势,对公众进行违法犯罪防范的科普教育变得尤为重要。该平台利用Django框架提供的高效且可扩展的特性,实现了用户注册与登录、科普文章发布与......
  • NetDiag 是一个由 Microsoft 提供的网络诊断工具,用于帮助管理员和用户诊断和排除网络
    Netdiag|MicrosoftLearnNetDiag是一个由Microsoft提供的网络诊断工具,用于帮助管理员和用户诊断和排除网络连接和配置方面的问题。它主要用于在Windows操作系统中分析和诊断与网络连接相关的问题,尤其是在ActiveDirectory环境中的问题。起源和历史背景:早期的网络诊......
  • 必备的计算机软件专业资料汇总,包括:计算机专业实习报告,计算机毕业设计成品(含源码和论
    大学期间必备的计算机软件专业资料汇总,包括:计算机专业实习报告(58篇)、计算机毕业设计成品(含源码和论文,1900多套,包括C语言/PHP/VB/java/JSP/Andorid/Python/微信小程序等)、HTML+CSS+JS速查参考手册(收藏版)、42套div+css模板专题模板(各风格和行业应用网站模板),等等。此资料仅用于学习参......
  • CTF学习24.11.7[日志分析和流量分析]
    MISC03日志分析和流量分析01日志分析什么是日志?Web访问日志记录了Web服务器接收处理请求及运行时错误等各种原始信息。通过对Web日志进行的安全分析,不仅可以帮助我们定位攻击者,还可以帮助我们还原攻击路径,找到网站存在的安全漏洞并进行修复。日志记录的内容计算机日志是......
  • Python基于Flask的前程无忧招聘信息可视化系统【附源码,文档】
    博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w+、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌......