当前位置: 首页 > news >正文

FutureTask配合Thread实现处理有返回结果的源码、逻辑与架构分析

文章目录

  • 1.介绍
  • 2.使用示例
  • 3.执行过程描述
  • 4.整体的关系
  • 5.涉及到的核心源码(只提取了关键代码)
    • 5.1 Callable
    • 5.2 RunnableFuture
    • 5.3 FutureTask
    • 5.4 Thread

1.介绍

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况。

2.使用示例

// 创建任务对象
FutureTask<Integer> task = new FutureTask<>(() -> {log.debug("running");Thread.sleep(1000);return 200;
});new Thread(task).start();// 主线程阻塞,同步等待 task 执行完毕的结果
Integer value = task.get();System.out.println("value = " + value);

3.执行过程描述

  1. FutureTask 类在实例化构造时需要传入一个实现了 Callable 接口的类,实现 Callable 接口需要重写 call 方法,该方法需要一个返回值,由于 Callable 定义时是以泛型定义返回值,因此我们可以自定义返回值。FutureTask 会将传入的这个 Callable 实现类赋给自己的属性 private Callable<V> callable;
  2. FutureTask 间接实现了 Runnable 接口,并重写了 run 方法,重写的 run 方法中会调用到 属性 callable 的 call 方法,并将 call 方法返回值存储到自己的属性 private Object outcome;
  3. Thread 类在实例化构造时可以传入一个 Runnable 接口的类,由于 FutureTask 实现了 Runnable 接口,因此我们可以直接将 FutureTask 对象作为构造器实参赋给 Thread对象的属性 private Runnable target;
  4. Thread 对象调用 start 方法,最终会调用到自身就重写了的 run 方法,自身重写的 run 方法中又会调用到 target 的 run 方法,即 FutureTask 自身已经重写的 run 方法,这时候就可以回到“第 2 点讲解”,了解到 FutureTask 的 run 方法中所做的事情。
  5. FutureTask 对象的 get() 方法,是去获取 callable 的 call 方法返回值,即属性 outcome 的值。get 方法中会调用 awaitDone 方法,awaitDone 方法中会使用 for (;;) 造成当前线程阻塞,直到 call 方法执行结束可以获取到 outcome 的值,并将 outcome 作为 get() 方法返回值。

4.整体的关系

Thread 和 FutureTask 类均实现了 Runnable 接口并重写了其 run 方法,Thread 将 FutureTask 进行聚合赋给 private Runnable target

5.涉及到的核心源码(只提取了关键代码)

5.1 Callable

@FunctionalInterface
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}

5.2 RunnableFuture

public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}

5.3 FutureTask

public class FutureTask<V> implements RunnableFuture<V> {/** The underlying callable; nulled out after running */private Callable<V> callable;// 存储 callable 接口的 call 方法的返回值/** The result to return or exception to throw from get() */private Object outcome; // non-volatile, protected by state reads/writes/*() -> {log.debug("running");Thread.sleep(1000);return 200;}这实际上是对函数式接口 callable 的 V call() 方法进行实现*/public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}   public void run() {// ...Callable<V> c = callable;// 重写了 Runnable 函数式接口的 run 方法result = c.call();// ...// 赋值set(result);// ...}protected void set(V v) {if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {// 将 callable 的 call 方法返回值,即我们自定义的 200 赋给 outcomeoutcome = v;UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final statefinishCompletion();}}// 获取 callable 的 call 方法的返回结果public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)// 获取到结果成功的标识,实际是在 awaitDone 方法中用了死循环不断判断是否生成返回结果,造成了线程阻塞s = awaitDone(false, 0L);// 获取结果return report(s);}// timed-是否计时等待,即是否设置等待超时,false表示不设置,true表示设置private int awaitDone(boolean timed, long nanos)throws InterruptedException {final long deadline = timed ? System.nanoTime() + nanos : 0L;WaitNode q = null;boolean queued = false;// 死循环for (;;) {if (Thread.interrupted()) {removeWaiter(q);throw new InterruptedException();}int s = state;if (s > COMPLETING) {if (q != null)q.thread = null;return s;}else if (s == COMPLETING) // cannot time out yetThread.yield();else if (q == null)q = new WaitNode();else if (!queued)queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);else if (timed) {nanos = deadline - System.nanoTime();if (nanos <= 0L) {removeWaiter(q);return state;}LockSupport.parkNanos(this, nanos);}elseLockSupport.park(this);}}
}

5.4 Thread

public class Thread implements Runnable {/* What will be run. */private Runnable target;// 构造器,将间接实现了 Runnable 接口的 FutureTask 对象传进来public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}private void init(ThreadGroup g, Runnable target, String name, long stackSize) {init(g, target, name, stackSize, null, true);}private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {// ...// 将 FutureTask 对象赋给 Thread 对象的属性 targetthis.target = target;}@Overridepublic void run() {if (target != null) {// 实际调用的 FutureTask 对象重写的 run 方法,重写的 run 方法中又会调用 callable 接口的 call 方法,并将 call 方法的返回值赋给 FutureTask 对象的属性 outcometarget.run();}}
}

相关文章:

FutureTask配合Thread实现处理有返回结果的源码、逻辑与架构分析

文章目录 1.介绍2.使用示例3.执行过程描述4.整体的关系5.涉及到的核心源码&#xff08;只提取了关键代码&#xff09;5.1 Callable5.2 RunnableFuture5.3 FutureTask5.4 Thread 1.介绍 FutureTask 能够接收 Callable 类型的参数&#xff0c;用来处理有返回结果的情况。 2.使用…...

Queue Deque 介绍

目录 一. 前言 二. Queue 接口 三. Deque 接口 一. 前言 Java里有一个叫做Stack的类&#xff0c;却没有叫做Queue的类&#xff08;它是个接口名字&#xff09;。当需要使用栈时&#xff0c;Java已不推荐使用Stack&#xff0c;而是推荐使用更高效的ArrayDeque&#xff1b;既然…...

机器学习(23)---Boosting tree(课堂笔记)

文章目录 一、知识记录二、题目2.1 题目12.2 题目22.3 答案书写 一、知识记录 二、题目 2.1 题目1 2.2 题目2 2.3 答案书写...

Excel 导出打不开

$filename iconv("UTF-8", "GB2312//IGNORE", 志愿者列表) . - . date(YmdHis) . .xlsx; header(Content-Type: application/vnd.ms-excel); header(Content-Disposition: attachment;filename".$filename."); header(Cache-Control: max-age0)…...

css钟表数字样式

如图&#xff1a; 代码 font-size: 28px;font-family: Yourname;font-weight: 500;color: #00e8ff;...

一步一步分析ChatGPT,1 粘性,2 传染性, 3 双边网络效应

请按照以下三个维度一步一步分析ChatGPT&#xff0c;1 粘性&#xff0c;2 传染性&#xff0c; 3 双边网络效应&#xff0c;比如亚马逊的买家和商家的关系 ChatGPT的分析 1.1. 粘性 (Stickiness) 定义&#xff1a; 粘性是指产品或服务对用户的吸引力&#xff0c;即用户在使用…...

Arthas(阿尔萨斯):阿里巴巴开源的线上问题诊断工具

背景 通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用 IDE 远程调试。更糟糕的是,在生产环境中调试是不可接受的,因为它会暂停所有线程,导致服务暂停。 开发人员可以尝试在测试环境或者预发环境中复现生产环境中的问题。但是,某些问题无法在不同…...

由Django-Session配置引发的反序列化安全问题

漏洞成因 漏洞成因位于目标配置文件settings.py下 关于这两个配置项 SESSION_ENGINE&#xff1a; 在Django中&#xff0c;SESSION_ENGINE 是一个设置项&#xff0c;用于指定用于存储和处理会话&#xff08;session&#xff09;数据的引擎。 SESSION_ENGINE 设置项允许您选择不…...

16-spring AOP核心对象的创建

文章目录 1. aop的几个重要概念2. aop bean definition3. AspectJPointcutAdvisor4.AopConfigUtils5.AnnotationAwareAspectJAutoProxyCreator6. 循环依赖1. aop的几个重要概念 参考官方解释:https://docs.spring.io/spring-framework/docs/5.2.9.RELEASE/spring-framework-r…...

Golang 泛型的介绍

引言 Golang是一种现代的编程语言&#xff0c;以其简洁的语法和高效的性能而闻名。然而&#xff0c;与其他一些编程语言相比&#xff0c;Golang在语言层面上缺乏泛型的支持&#xff0c;这使得在处理不同类型的数据时变得有些困难。在本文中&#xff0c;我们将介绍Golang泛型的…...

RK3568笔记四:基于TensorFlow花卉图像分类部署

若该文为原创文章&#xff0c;转载请注明原文出处。 基于正点原子的ATK-DLRK3568部署测试。 花卉图像分类任务&#xff0c;使用使用 tf.keras.Sequential 模型&#xff0c;简单构建模型&#xff0c;然后转换成 RKNN 模型部署到ATK-DLRK3568板子上。 在 PC 使用 Windows 系统…...

甄知科技张礼军:数智化转型助企业破茧成蝶!

数智化浪潮滚滚向前&#xff0c;正席卷各行各业&#xff0c;带领企业从数字化时代跨入数智化时代。可什么是数智化&#xff1f;如何实现数智化转型&#xff1f;已经成为横亘在无数企业面前的大难题&#xff01; 事实上&#xff0c;数智化是数字化、AI和业务三个要素的交集&…...

Golang Map:高效的键值对容器

1. 引言 在编程中&#xff0c;我们经常需要使用键-值对来存储和操作数据。Golang中提供了一种高效的键值对容器——Map&#xff08;映射&#xff09;&#xff0c;它提供了快速的查找和插入操作&#xff0c;是处理大量关联数据的理想选择。本文将介绍Golang中的Map&#xff0c;…...

2023年【电工(高级)】报名考试及电工(高级)模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年【电工&#xff08;高级&#xff09;】报名考试及电工&#xff08;高级&#xff09;模拟考试题&#xff0c;包含电工&#xff08;高级&#xff09;报名考试答案和解析及电工&#xff08;高级&#xff09;模拟考…...

伊朗相关的OilRig组织在为期8个月的网络攻击中针对中东政府

导语 伊朗相关的OilRig组织最近在中东政府中展开了一场长达8个月的网络攻击行动。这次攻击导致了文件和密码的被窃取&#xff0c;并且在其中一次攻击中&#xff0c;攻击者还使用了一种名为PowerExchange的PowerShell后门。据Symantec的威胁猎人团队称&#xff0c;他们在一份与T…...

服务器数据恢复-linux+raid+VMwave ESX数据恢复案例

服务器数据恢复环境&#xff1a; 一台某品牌x3950 X6型号服务器&#xff0c;linux操作系统&#xff0c;12块硬盘组建了一组raid阵列&#xff0c;上层运行VMwave ESX虚拟化平台。 服务器故障&#xff1a; 在服务器运行过程中&#xff0c;该raid阵列中有硬盘掉线&#xff0c;linu…...

残疾人求助报警器

残疾人求助报警器 实际上&#xff0c;求助报警对残疾人来说并不是一件容易的事情。首先&#xff0c;由于身体上的缺陷&#xff0c;他们在描述事件经过和罪犯体征时往往存在困难。此外&#xff0c;一些残疾人可能因为自卑或担心被歧视而犹豫不决&#xff0c;甚至选择忍气吞声。…...

【Datawhale】扩散模型学习笔记 第一次打卡

文章目录 扩散模型学习笔记1. 扩散模型库Diffusers1.1 安装1.2 使用 2. 从零开始搭建扩散模型2.1 数据准备2.2 损坏过程2.3 模型构建2.4 模型训练2.5 采样 3. webui 扩散模型学习笔记 1. 扩散模型库Diffusers 1.1 安装 由于diffusers库更新较快&#xff0c;所以建议时常upgr…...

Spring Boot学习笔记

SpringBoot特征 特征 创建独立的 Spring 应用程序 直接嵌入 Tomcat、Jetty 或 Undertow&#xff08;无需部署 WAR 文件&#xff09; 提供“入门”依赖项以简化构建配置 尽可能自动配置 Spring 和 第三方库 提供生产就绪功能&#xff0c;例如指标、健康检查和外部化配置 完…...

图像边缘检测--(Sobel、Laplacian、Canny)

1、图像中各种形状的检测是计算机视觉领域中非常常见的技术之一,特别是图像中直线的检测,圆的检测,图像边缘的检测等,下面将介绍如何快速检测图像边缘。 2、边缘是不同区域的分界线,是周围(局部)像素有显著变化的像素的集合,有幅值与方向两个属性。这个不是绝对的定义,…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...