广告
返回顶部
首页 > 资讯 > 精选 >Java异步编程中如何进行FutureTask源码分析
  • 587
分享到

Java异步编程中如何进行FutureTask源码分析

2023-06-19 10:06:21 587人浏览 泡泡鱼
摘要

本篇文章给大家分享的是有关Java异步编程中如何进行FutureTask源码分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的异步编程是一项非常常用的多线程技术。但之

本篇文章给大家分享的是有关Java异步编程中如何进行FutureTask源码分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

Java的异步编程是一项非常常用的多线程技术。

但之前的任务主要倾向于线程池,并没有讲到异步编程方面的内容。

万事从示例开始,我们先通过示例Demo有一个直观的印象,再深入去了解概念与原理。

使用示例

Java异步编程中如何进行FutureTask源码分析

使用上比较简单,

运行结果:

任务1异步执行:0任务2异步执行:0任务2异步执行:1...任务2异步执行:45同步代码任务2异步执行:24...任务1异步执行:199任务1:执行完成...任务2异步执行:199任务2:执行完成

假若你多次执行这个程序,会发现结果大大的不一样,因为两个任务和同步代码是异步由多条线程执行的,打印的结果当然是随机的。

回顾这个Demo做了什么,

  1. 构建了一个线程池

  2. 往线程池里面丢两个需要执行的任务

  3. 最后获取这两个任务的结果

其中第二点是异步执行两个任务,这两个任务和主线程分别是用了三个线程并发执行的,第三点是在主线程中同步等待两个任务的结果。

很容易看出来,异步编程的好处就在于可以让不相干的任务异步执行,不阻塞主线程。若是主线程需要异步执行的结果,此时再去等待结果会更加高效,提高程序的执行效率。

下面来看看整个流程的实现原理。

源码分析

一般在实际项目中,都会有配置有自己的线程池,建议大家在用异步编程时,配置一个专用的线程池,做好线程隔离,避免异步线程影响到其他模块的工作。Demo中为了方便,直接调用Exectors的方法生成一个临时的线程池,日常不建议使用。

我们从这个ExecutorService.submit()方法入手,看看整体实现。

Java异步编程中如何进行FutureTask源码分析

ExecutorService.submit()定义一个接口。这个接口接收一个Callable参数(执行的任务),返回一个Future(计算结果)。

Callable,相当于一个需要执行的任务。它不接收任何参数,可以返回结果,可以抛出异常。相类似的还有Runnable,它也是不接收,不同点在于它不返回结果,也不抛异常,异常需要在任务内部处理。总结来说Callable更像一个方法的调用,Runnable则是一个不需要理会结果的调用。在jdk 8以后,它们都可以通过Lamda表达式写法去替代内部类的写法(详见Demo)。

Future,一个异步计算的结果。调用get()方法可以得到对应的计算结果,如果调用时没有异步计算完,会阻塞等待计算的结果。同时它还提供方法可以尝试取消任务的执行。

看回ExecutorService.submit()的实现,代码在实现类AbstractExecutorService中。

Java异步编程中如何进行FutureTask源码分析

除了它接口的实现,还提供了两种变形。原来接口只接收Callable参数,实现类中还新增了接收Runnable参数的。

如果看过之前写的《你真的懂ThreadPoolExecutor线程池技术吗?看了源码你会有全新的认识》,应该了解ThreadPoolExecutor执行任务是可以调用execute()方法的。而这里面submit()方法则是为Callable/Runnable加多一层FutureTask,从而 使执行结果有一个存放的地方,同时也添加一个可以取消的功能。原本的execute()只能执行任务,不会返回结果的,具体实现原理可以看看之前的文章分析。

FutureTaskRunnableFuture的实现。而RunnableFuture是继承FutureRunnable接口的,定义run()接口。

Java异步编程中如何进行FutureTask源码分析

因为FutureTaskrun()接口,所以可以直接用一个Callable/Runnable创建一个FutureTask单独执行。但这样并没有异步的效果,因为没有启用新的线程去跑,而是在原来的线程阻塞执行的。

到这里我们清楚知道了,submit()方法重点是利用Callable/Runnable创建一个FutureTask,然后多线程执行run()方法,达到异步处理并且得到结果的效果。而FutureTask的重点则是run()方法如何持有保存计算的结果。

FutureTask.run()

Java异步编程中如何进行FutureTask源码分析

首先判断futureTask对象的state状态,如果不是NEW的话,证明已经开始运行过了,则退出执行。同时futureTask对象通过CAS,把当前线程赋值给变量runner(是Thread类型,说明对象使用哪个线程执行的),如果CAS失败则退出。

外层try{}代码块中,对callable判空和state状态必须是NEW。内层try{}代码真正调用callable,开始执行任务。若执行成功,则把ran变量设为true,保存结果在result变量中,证明已跑成功过了;若抛异常了,则设为false,result为空,并且调用setException()保存异常。最后如果ran为true的话,则调用set()保存result结果。

看下setException()set()的实现。 Java异步编程中如何进行FutureTask源码分析

两者的基本流程一样,CAS置换状态,保存结果在outcome变量道中,但setException()保存的结果类型固定是Throwable。另外一个不同在于最终state状态,一个是EXCEPTION,一个是NORMAL。

这两个方法最后都调用了finishCompletion()。这个方法主要是配合线程池唤醒下一个任务。

FutureTask.get()

从上面run()方法得知,最后执行的结果放在了outcome变量中。那最终怎么从其中取出结果来,我们来看看get()方法。

Java异步编程中如何进行FutureTask源码分析

从源码可知,get()方法分两步。第一步,先判断状态,如果计算为完成,则需要阻塞地等待完成。第二步,如果完成了,则调用report()方法获取结果并返回。

先看看awaitDone()阻塞等待完成。该方法可以选用超时功能。

Java异步编程中如何进行FutureTask源码分析

在自旋的for()循环中,

  • 先判断是否线程被中断,中断的话抛异常退出。

  • 然后开始判断运行的state值,如果state大于COMPLETING,证明计算已经是终态了,此时返回终态变量。

  • state等于COMPLETING,证明已经开始计算,并且还在计算中。此时为了避免过多的CPU时间放在这个for循环的自旋上,程序执行Thread.yield(),把线程从运行态降为就绪态,让出CPU时间。

  • 若以上状态都不是,则证明stateNEW,还没开始执行。那么程序在当前循环现在会新增一个Waitnode,在下一个循环里面调用 LockSupport.park()把当前线程阻塞。当run()方法结束的时候,会再次唤醒此线程,避免自旋消耗CPU时间。

  • 如果选用了超时功能,在阻塞和自旋过程中超时了,则会返回当前超时的状态。

第二步的report()方法比较简单。

Java异步编程中如何进行FutureTask源码分析

  • 如果状态是NORMAL,正常结束的话,则把outcome变量返回;

  • 如果是取消或者中断状态的,则抛出取消异常;

  • 如果是EXCEPTION,则把outcome当作异常抛出(之前setException()保存的类型就是Throwable)。从而整个get()会有一个异常抛出。

至此我们已经比较完整地了解Executor+Future的框架原理了,而FutureTask则是该框架的主要实现。下面总结下要点

  1. Executor.sumbit()方法异步执行一个任务,并且返回一个Future结果。

  2. submit()的原理是利用Callable创建一个FutureTask对象,然后执行对象的run()方法,把结果保存在outcome中。

  3. 调用get()获取outcome时,如果任务未完成,会阻塞线程,等待执行完毕。

  4. 异常和正常结果都放在outcome中,调用get()获取结果或抛出异常。

以上就是Java异步编程中如何进行FutureTask源码分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网精选频道。

--结束END--

本文标题: Java异步编程中如何进行FutureTask源码分析

本文链接: https://www.lsjlt.com/news/295313.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java异步编程中如何进行FutureTask源码分析
    本篇文章给大家分享的是有关Java异步编程中如何进行FutureTask源码分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的异步编程是一项非常常用的多线程技术。但之...
    99+
    2023-06-19
  • 如何分析Java中的异步网络编程
    如何分析Java中的异步网络编程,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。目前java平台已经广泛应用于各类客户/服务器系统中,在实际编程中,往往需要网络的...
    99+
    2023-06-03
  • Java中如何使用Git进行异步编程?
    Git是一种非常流行的版本控制工具,它可以帮助开发人员更好地管理代码,协作开发和版本控制。在Java编程中,异步编程已经成为一种非常重要的技术,它可以帮助开发人员更好地处理大量的并发任务。本文将介绍如何在Java中使用Git进行异步编程。...
    99+
    2023-10-11
    git 异步编程 日志
  • 如何进行C++代码的异步编程?
    如何进行C++代码的异步编程?在软件开发领域,异步编程(Asynchronous Programming)成为了必备技能之一。它可以更好地平衡CPU密集型操作和IO密集型操作的性能,使程序代码并发或并行执行,进而提高了程序的响应速度和整体性...
    99+
    2023-11-02
    异步(Async) 异步编程步骤: 线程(Thread) 回调(Callback)
  • Java编程中如何优化重定向和异步编程的同时进行资源加载?
    Java编程中,对于重定向和异步编程的处理,以及同时进行资源加载,需要注意一些优化技巧。本文将介绍如何优化这些方面,并为您提供一些演示代码。 重定向优化 重定向是指在一个URL请求中,服务器将客户端请求的URL重定向到另一个URL。在...
    99+
    2023-11-07
    重定向 异步编程 load
  • JS中的async与await异步编程及await使用陷阱源码分析
    这篇“JS中的async与await异步编程及await使用陷阱源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JS中...
    99+
    2023-07-05
  • 如何在Linux环境下进行Java异步编程?
    在Java编程中,异步编程是一项非常重要的技能。它可以让我们更好地处理并发任务,提高程序的性能和响应速度。在Linux环境下进行Java异步编程,可以使用多种技术和框架。本文将介绍如何在Linux环境下使用Java的异步编程技术,以及如何使...
    99+
    2023-09-16
    数据类型 linux 异步编程
  • 如何进行C#网络编程客户端程序的实现源码分析
    本篇文章给大家分享的是有关如何进行C#网络编程客户端程序的实现源码分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#网络编程客户端程序实现是如何办到的呢?由于在客户端不需要...
    99+
    2023-06-17
  • 如何在Java程序中实现异步编程和重定向同时进行资源加载?
    Java是一种广泛使用的编程语言,它提供了许多工具和库,以帮助开发人员更快地编写高质量的应用程序。在Java应用程序中,异步编程和重定向同时进行资源加载是两个常见的需求。本文将介绍如何在Java程序中实现这两个需求。 一、什么是异步编程? ...
    99+
    2023-11-07
    重定向 异步编程 load
  • PHP 中如何使用 NPM 进行异步编程?
    在 PHP 中进行异步编程是一件困难的事情,因为 PHP 是一种同步语言。但是,我们可以使用 Node.js 的包管理器 NPM 来实现异步编程。 NPM 是一个包管理器,它允许我们安装、更新和管理 Node.js 的模块。在 PHP 中...
    99+
    2023-09-12
    npm 异步编程 linux
  • 如何进行数据库中间件 MyCAT 源码分析
    这篇文章将为大家详细讲解有关如何进行数据库中间件 MyCAT 源码分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1. 概述可能你在看到这个标题会小小的吃...
    99+
    2022-10-19
  • 如何在Java学习笔记中使用npm进行异步编程?
    Java是一门流行的编程语言,它的使用范围广泛,从Web应用到移动应用再到桌面应用,Java都有着广泛的应用。在Java中,异步编程是一种常见的编程方式,它可以提高程序的性能和响应性。而在Java学习笔记中,我们可以使用npm进行异步编程。...
    99+
    2023-07-21
    学习笔记 npm 异步编程
  • 如何使用Python中的协程进行异步编程
    如何使用Python中的协程进行异步编程在传统的同步编程模型中,一个任务必须等待另一个任务完成后才能继续进行,这样会造成程序的执行效率降低。为了解决这个问题,异步编程模型应运而生。Python中的协程是一种支持异步编程的重要概念,它可以让我...
    99+
    2023-10-28
    Python 协程 异步编程
  • ASP中如何使用数组进行异步编程?
    在ASP(Active Server Pages)中,异步编程是一种非常重要的技术,它可以提高Web应用程序的性能和响应速度。其中,数组是一种非常常见的数据结构,能够方便地存储和处理多个数据。本文将介绍如何在ASP中使用数组进行异步编程。...
    99+
    2023-11-13
    数组 ide 异步编程
  • Java中如何利用对象进行异步编程和并发处理?
    Java作为一种面向对象的编程语言,其强大的对象模型和线程机制使得其在异步编程和并发处理方面有着广泛的应用。在本文中,我们将介绍Java中利用对象进行异步编程和并发处理的方法,并且会给出相应的演示代码。 一、Java中的线程机制 Java中...
    99+
    2023-07-19
    对象 异步编程 并发
  • 如何用ES7中的Async和Await进行异步编程
    这篇文章给大家介绍如何用ES7中的Async和Await进行异步编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Async/Await基本规则async 表示这是一个async函数,...
    99+
    2022-10-19
  • 如何在Go中使用数组进行异步编程?
    在Go语言中,使用数组进行异步编程是非常常见的操作。在本文中,我们将介绍如何在Go语言中使用数组进行异步编程,并提供一些实际的例子来帮助你更好地理解。 什么是异步编程? 在传统的同步编程中,程序会按照顺序执行每个操作,直到完成所有操作。...
    99+
    2023-10-02
    数组 异步编程 关键字
  • 如何在Linux中使用IDE进行Python异步编程?
    在Linux中使用IDE进行Python异步编程可以大大提高代码编写效率和程序运行速度。本文将介绍如何使用PyCharm IDE进行Python异步编程。 一、什么是异步编程? 异步编程是一种编程模式,它能够提高程序的运行效率。在异步编程中...
    99+
    2023-09-02
    异步编程 linux ide
  • Java异步编程:如何在分布式系统中实现?
    随着分布式系统的普及,异步编程成为了必不可少的一部分。Java作为一种广泛使用的编程语言,也在异步编程方面提供了很多支持。本文将介绍Java异步编程的基础知识,并探讨如何在分布式系统中实现异步编程。 一、异步编程基础 异步编程是指在执行某...
    99+
    2023-07-31
    异步编程 分布式 关键字
  • 如何在Windows上使用Java IDE进行高效的异步编程?
    在现代软件开发中,异步编程已经成为了必不可少的一部分。它可以帮助我们利用多核 CPU,提高程序的响应速度和性能。而在 Java 开发中,使用 Java IDE 进行异步编程可以大大提高我们的编码效率。本文将介绍如何在 Windows 上使用...
    99+
    2023-07-22
    ide windows 异步编程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作