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.执行过程描述
- FutureTask 类在实例化构造时需要传入一个实现了 Callable 接口的类,实现 Callable 接口需要重写 call 方法,该方法需要一个返回值,由于 Callable 定义时是以泛型定义返回值,因此我们可以自定义返回值。FutureTask 会将传入的这个 Callable 实现类赋给自己的属性
private Callable<V> callable; - FutureTask 间接实现了 Runnable 接口,并重写了 run 方法,重写的 run 方法中会调用到 属性 callable 的 call 方法,并将 call 方法返回值存储到自己的属性
private Object outcome; - Thread 类在实例化构造时可以传入一个 Runnable 接口的类,由于 FutureTask 实现了 Runnable 接口,因此我们可以直接将 FutureTask 对象作为构造器实参赋给 Thread对象的属性
private Runnable target; - Thread 对象调用 start 方法,最终会调用到自身就重写了的 run 方法,自身重写的 run 方法中又会调用到 target 的 run 方法,即 FutureTask 自身已经重写的 run 方法,这时候就可以回到“第 2 点讲解”,了解到 FutureTask 的 run 方法中所做的事情。
- 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.涉及到的核心源码(只提取了关键代码)5.1 Callable5.2 RunnableFuture5.3 FutureTask5.4 Thread 1.介绍 FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况。 2.使用…...
Queue Deque 介绍
目录 一. 前言 二. Queue 接口 三. Deque 接口 一. 前言 Java里有一个叫做Stack的类,却没有叫做Queue的类(它是个接口名字)。当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque;既然…...
机器学习(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钟表数字样式
如图: 代码 font-size: 28px;font-family: Yourname;font-weight: 500;color: #00e8ff;...
一步一步分析ChatGPT,1 粘性,2 传染性, 3 双边网络效应
请按照以下三个维度一步一步分析ChatGPT,1 粘性,2 传染性, 3 双边网络效应,比如亚马逊的买家和商家的关系 ChatGPT的分析 1.1. 粘性 (Stickiness) 定义: 粘性是指产品或服务对用户的吸引力,即用户在使用…...
Arthas(阿尔萨斯):阿里巴巴开源的线上问题诊断工具
背景 通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用 IDE 远程调试。更糟糕的是,在生产环境中调试是不可接受的,因为它会暂停所有线程,导致服务暂停。 开发人员可以尝试在测试环境或者预发环境中复现生产环境中的问题。但是,某些问题无法在不同…...
由Django-Session配置引发的反序列化安全问题
漏洞成因 漏洞成因位于目标配置文件settings.py下 关于这两个配置项 SESSION_ENGINE: 在Django中,SESSION_ENGINE 是一个设置项,用于指定用于存储和处理会话(session)数据的引擎。 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是一种现代的编程语言,以其简洁的语法和高效的性能而闻名。然而,与其他一些编程语言相比,Golang在语言层面上缺乏泛型的支持,这使得在处理不同类型的数据时变得有些困难。在本文中,我们将介绍Golang泛型的…...
RK3568笔记四:基于TensorFlow花卉图像分类部署
若该文为原创文章,转载请注明原文出处。 基于正点原子的ATK-DLRK3568部署测试。 花卉图像分类任务,使用使用 tf.keras.Sequential 模型,简单构建模型,然后转换成 RKNN 模型部署到ATK-DLRK3568板子上。 在 PC 使用 Windows 系统…...
甄知科技张礼军:数智化转型助企业破茧成蝶!
数智化浪潮滚滚向前,正席卷各行各业,带领企业从数字化时代跨入数智化时代。可什么是数智化?如何实现数智化转型?已经成为横亘在无数企业面前的大难题! 事实上,数智化是数字化、AI和业务三个要素的交集&…...
Golang Map:高效的键值对容器
1. 引言 在编程中,我们经常需要使用键-值对来存储和操作数据。Golang中提供了一种高效的键值对容器——Map(映射),它提供了快速的查找和插入操作,是处理大量关联数据的理想选择。本文将介绍Golang中的Map,…...
2023年【电工(高级)】报名考试及电工(高级)模拟考试题
题库来源:安全生产模拟考试一点通公众号小程序 2023年【电工(高级)】报名考试及电工(高级)模拟考试题,包含电工(高级)报名考试答案和解析及电工(高级)模拟考…...
伊朗相关的OilRig组织在为期8个月的网络攻击中针对中东政府
导语 伊朗相关的OilRig组织最近在中东政府中展开了一场长达8个月的网络攻击行动。这次攻击导致了文件和密码的被窃取,并且在其中一次攻击中,攻击者还使用了一种名为PowerExchange的PowerShell后门。据Symantec的威胁猎人团队称,他们在一份与T…...
服务器数据恢复-linux+raid+VMwave ESX数据恢复案例
服务器数据恢复环境: 一台某品牌x3950 X6型号服务器,linux操作系统,12块硬盘组建了一组raid阵列,上层运行VMwave ESX虚拟化平台。 服务器故障: 在服务器运行过程中,该raid阵列中有硬盘掉线,linu…...
残疾人求助报警器
残疾人求助报警器 实际上,求助报警对残疾人来说并不是一件容易的事情。首先,由于身体上的缺陷,他们在描述事件经过和罪犯体征时往往存在困难。此外,一些残疾人可能因为自卑或担心被歧视而犹豫不决,甚至选择忍气吞声。…...
【Datawhale】扩散模型学习笔记 第一次打卡
文章目录 扩散模型学习笔记1. 扩散模型库Diffusers1.1 安装1.2 使用 2. 从零开始搭建扩散模型2.1 数据准备2.2 损坏过程2.3 模型构建2.4 模型训练2.5 采样 3. webui 扩散模型学习笔记 1. 扩散模型库Diffusers 1.1 安装 由于diffusers库更新较快,所以建议时常upgr…...
Spring Boot学习笔记
SpringBoot特征 特征 创建独立的 Spring 应用程序 直接嵌入 Tomcat、Jetty 或 Undertow(无需部署 WAR 文件) 提供“入门”依赖项以简化构建配置 尽可能自动配置 Spring 和 第三方库 提供生产就绪功能,例如指标、健康检查和外部化配置 完…...
图像边缘检测--(Sobel、Laplacian、Canny)
1、图像中各种形状的检测是计算机视觉领域中非常常见的技术之一,特别是图像中直线的检测,圆的检测,图像边缘的检测等,下面将介绍如何快速检测图像边缘。 2、边缘是不同区域的分界线,是周围(局部)像素有显著变化的像素的集合,有幅值与方向两个属性。这个不是绝对的定义,…...
LangSmith + LangGraph 完整打通 + 全链路追踪调试
LangGraph RAG 每一步:检索、重排、LLM 调用、耗时、参数,全部可视化追踪、调试、打分、日志留存。 一、先搞懂:LangSmith 到底做什么? LangSmith = LLM 应用的黑匣子 + 调试控制台 它能帮你看到: 每个节点执行了什么 检索到了哪些文档 LLM 输入 / 输出是什么 耗时、报错…...
如何在3秒内从任何图片提取文字:Text-Grab终极指南
如何在3秒内从任何图片提取文字:Text-Grab终极指南 【免费下载链接】Text-Grab Use OCR in Windows quickly and easily with Text Grab. With optional background process and notifications. 项目地址: https://gitcode.com/gh_mirrors/te/Text-Grab 你是…...
PL111 RGB LCD时序配置详解
PL111 RGB LCD 时序说明 1)文档范围 本文从两个维度整理 PL111 时序: 通俗理解(面向调试与沟通)硬件寄存器映射(面向实现与定位问题) 内容与 bsp/qemu-vexpress-a9/drivers/drv_clcd.c 的实现保持一致。2&a…...
别再买分立元件了!用Matlab脚本快速设计微带线等效电感电容(附ADS验证)
射频PCB设计革命:用Matlab脚本实现微带线等效LC元件的工程实践 在毫米波和5G时代,射频电路设计工程师们正面临着一个共同的困境:如何在有限的PCB空间内实现高性能的LC元件布局?传统的高频贴片电感和电容不仅价格昂贵、供货周期长&…...
SteamShutdown智能关机完整指南:告别游戏下载后的能源浪费
SteamShutdown智能关机完整指南:告别游戏下载后的能源浪费 【免费下载链接】SteamShutdown Automatic shutdown after Steam download(s) has finished. 项目地址: https://gitcode.com/gh_mirrors/st/SteamShutdown 你是否曾经在深夜设置好Steam游戏下载后安…...
Mobaxterm连接不上CentOS 7?先检查这3个服务(附Windows服务开启方法)
Mobaxterm连接CentOS 7终极排障指南:从服务层到网络配置的深度解析 当你盯着Mobaxterm那个迟迟不响应的终端窗口,心里可能已经默念了无数遍"为什么连不上"。大多数教程会告诉你检查IP、防火墙或网络模式,但真正的问题往往藏在更深层…...
案例之 逻辑回归_癌症预测
案例:使用 逻辑回归模型 实现癌症预测 逻辑回归模型介绍: 1.概述:属于有监督学习,即有特征、有标签、且标签是离散的。主要适用于二分类; 2.原理:把线性回归处理后的预测值–>通过Sigmoid激活函数&#…...
Cursor Pro激活器架构深度解析:多平台身份管理系统的设计与实现
Cursor Pro激活器架构深度解析:多平台身份管理系统的设计与实现 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached…...
Qwen3.5-4B模型辅助C语言学习:代码调试与指针概念讲解
Qwen3.5-4B模型辅助C语言学习:代码调试与指针概念讲解 1. 为什么需要AI编程助教 学习C语言就像第一次学骑自行车——看着简单,但总会在指针和内存管理这些地方摔跟头。传统教学方式下,学生遇到问题往往要等到下次上课才能问老师,…...
Arduino IDE 2.2.1 + STM32:从C盘迁移库文件到D盘的完整避坑指南
Arduino IDE 2.2.1 STM32:从C盘迁移库文件到D盘的完整避坑指南 对于长期使用Arduino IDE开发STM32项目的工程师来说,C盘空间告急和系统重装后的配置恢复是两大痛点。当你的开发板支持包积累到5GB以上,当你的离线库文件占据大量空间ÿ…...
