java如何获取多线程的返回值?

        想要获取多线程的返回值,开启线程的方式就只能选择使用实现Callable接口的方式了,同实现Runnable接口的方式不同,实现Callable的方式有两大优点,第一个是能够获取到线程任务异步执行的结果,第二个是,当任务执行过程中发生了异常时,这个异常不止能够在任务内部处理,还可以向上抛出,也就是抛到call方法的外部来处理。

        Callable接口同Runnable接口一样,也是一个函数式接口,它内部只定义了一个抽象方法call方法,我们要在call方法内实现任务的具体业务逻辑;Callable接口定义了泛型,当实现Callable接口时,我们要为它指定泛型的具体类型,Callable接口的call方法是有返回值的,返回值的具体类型与接口上定义的泛型类型相同;call方法能够将执行过程中发生的异常向外抛出,所以它的方法声明上也声明了throws Exeception。java提供了Future接口和它的实现类FutureTask来协助我们实现跨线程式地获取Callable任务的执行结果,当我们的业务需求是需要获取线程任务的执行结果时,我们首先要创建一个Callable接口的实现类,或者是通过匿名内部类的方式来定义call方法的具体逻辑,然后创建一个Callable对象,将这个Callable对象作为构造参数传给FutureTask的构造器来构造一个FutureTask对象,再将这个FutureTask对象作为构造参数传给Thread类的构造器构造一个Thread对象,然后调用这个Thread对象的start方法去启动这个任务线程,最后就可以通过调用FutureTask对象的get方法来获取线程任务的异步执行的结果了。

        那么FutureTask对象的get方法是如果实现跨线程获取Callable任务的执行结果的呢?

        要实现这个功能,get方法首先要做的操作就是让调用它的线程进入阻塞状态,调用线程只有进入了阻塞状态才能等待任务线程执行完毕,才能去获取执行结果,否则可能任务线程还没执行完成而调用线程就执行完成退出了。在FutureTask类中定义了一个链表类型的成员变量,专门用于存放因为调用此FutureTask对象而进入阻塞状态的线程,当调用线程调用了FutureTask对象的get方法时,这个调用线程就进入阻塞状态然后被保存到这个链表中。

        FutureTask是如何执行Callable任务的呢?

        FutureTask这个类除了实现Future接口外,还实现了Runnable接口,这也是它能够作为Thread类的构造参数的原因,而Runnable接口的run方法即为线程的线程体,所以FutureTask对象所实现的run方法也就是任务线程的线程体,当任务线程被cpu调度到,进入running状态时,执行的就是FutureTask对象的run方法,而在FutureTask对象的run方法内部其实执行的是构造此TutureTask对象的那个Callable对象的call方法,也就是我们定义的任务的业务逻辑,当call方法执行完毕,就产生了任务结果,而这个结构就是那些调用线程所要获取的结构,FutureTask对象为了让那些线程获取到这个接口,所以设计了另外一个Object类型的成员变量outcome,用于保存call方法的执行结果,所以它会将结果赋值给这个outcome变量,赋值完成之后,run方法所要执行的下一步操作就是唤醒链表中阻塞着的线程了,它会遍历链表,将所有以为调用了get方法而进入阻塞状态的线程唤醒,当这些线程被唤醒之后,会去继续get方法的执行,也就是去FutureTask对象的outcome变量中获取任务执行结果,至此,就实现了任务结果的跨线程获取,也即实现了多线程返回值的获取。

        当然我们在实际的开发中,并不会用这种new Thread创建野生线程的方式来进行多线程编程,我们一般会用线程池来管理线程,线程池ExecutorService提供了submit方法用于往池中提交任务,这个方法有一个Future类型的返回值,我们可以使用这个方法来提交一个Callable或者Runnable类型的任务到线程池中,然后通过它返回的Future对象调用get方法来获取到任务的异步执行的结果,原理同上面讲的一样。所以当我们有获取多线程任务执行结果的业务需求时,要使用submit方法来提交任务而不是使用execute方法,因为execute方法没有返回值,我们也就无法通过返回对象来获取任务结果了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录 Leetcode102. 二叉树的层序遍历

题目&#xff1a; 代码(首刷看解析 2024年1月24日&#xff09;&#xff1a; class Solution { public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> res;if(root nullptr) return res;queue<TreeNode*> que;TreeNode…

C++笔记(三)

封装意义: 在设计类的时候&#xff0c;属性和行为写在一起&#xff0c;表现事物 类在设计时&#xff0c;可以把属性和行为放在不同的权限下&#xff0c;加以控制。 访问权限有三种&#xff1a; public 公共 类内 类外都可以访问&#xff0c; protected保护 类内可以访问…

蓝桥杯备战——5.动态数码管扫描

1.分析原理图 经查阅说明书得知数码管为共阳极&#xff0c;共阳端口接到了U8,而段码接到了U7。 如果需要选中U8,我们只需要将P250;P261;P271; 如果需要选中U7,我们只需要将P251;P261;P271; 2.代码示例 void Delay1ms() //12.000MHz {unsigned char data i, j;i 12;j 169;…

ubuntu20.04 格式化 硬盘 扩展硬盘GParted

如何在 Ubuntu 22.04 LTS 上安装分区编辑器 GParted&#xff1f;_gparted安装-CSDN博客 sudo apt install gparted 步骤5&#xff1a;启动GParted 安装完成后&#xff0c;您可以在应用程序菜单中找到GParted。点击它以启动分区编辑器。 通过以上步骤&#xff0c;您可以在Ubun…

【2024】新建mysql数据库,如何选择字符集和排序规则

如何使用 Navicat 新建 MySQL 数据库&#xff0c;并选择字符集与排序规则 如何使用 Navicat 新建 MySQL 数据库并选择字符集与排序规则1. 开始之前2. 新建数据库步骤 1: 打开 Navicat步骤 2: 创建新数据库步骤 3: 填写数据库名称 常见的字符集和排序规则及其选择场景1. 字符集&…

7.前端--CSS-复合选择器

1.什么是复合选择器 复合选择器是由两个或多个基础选择器&#xff0c;通过不同的方式组合而成的&#xff0c;可以更准确、更高效的选择目标元素&#xff08;标签&#xff09; 常用的复合选择器包括&#xff1a;后代选择器、子选择器、并集选择器、伪类选择器等等 2.后代选择器 …

定时器越走越快的原因

在上述例子中&#xff0c;本应每1秒输出一次&#xff0c;但在多次点击按钮后会变成每0.9秒、0.8秒、0.7秒… 就输出一次&#xff0c;即定时器时间间隔越来越短&#xff0c;这就是所谓的定时器越走越快。 其实原因很简单&#xff0c;在多次点击按钮时&#xff0c;多次创建了定时…

【卡梅德生物】单域抗体|纳米抗体|VHH文库构建

单域抗体&#xff0c;也称为VHH&#xff08;Variable domain of heavy chain of HCAb&#xff09;抗体或纳米抗体&#xff0c;是一种小型抗体分子。与传统抗体相比&#xff0c;VHH具有更小的分子尺寸、更高的稳定性和更易于工程化的特点&#xff0c;具有广泛的生物医学应用潜力…

LeetCode:670. 最大交换(Java 贪心)

目录 670. 最大交换 题目描述&#xff1a; 实现代码与解析&#xff1b; 贪心 原理思路&#xff1a; 670. 最大交换 题目描述&#xff1a; 给定一个非负整数&#xff0c;你至多可以交换一次数字中的任意两位。返回你能得到的最大值。 示例 1 : 输入: 2736 输出: 7236 解释…

flink基础概念之什么是时间语义

什么是时间语义 Flink支持三种不同的时间语义&#xff0c;以便处理流式数据中的事件时间、处理时间和摄入时间。 1. 处理时间&#xff08;Processing Time&#xff09; 处理时间的概念非常简单&#xff0c;就是指执行处理操作的机器的系统时间。 在这种时间语义下处理窗口非…

接口自动化测试实践

众所周知&#xff0c;接口自动化测试有着如下特点&#xff1a; 低投入&#xff0c;高产出。 比较容易实现自动化。 和UI自动化测试相比更加稳定。 如何做好一个接口自动化测试项目呢&#xff1f; 我认为&#xff0c;一个“好的”自动化测试项目&#xff0c;需要从“时间”…

05-Seata下SQL使用限制

不支持 SQL 嵌套不支持多表复杂 SQL(自1.6.0版本&#xff0c;MySQL支持UPDATE JOIN语句&#xff0c;详情请看不支持存储过程、触发器部分数据库不支持批量更新&#xff0c;在使用 MySQL、Mariadb、PostgreSQL9.6作为数据库时支持批量&#xff0c;批量更新方式如下以 Java 为例 …

掌握大语言模型技术: 推理优化

掌握大语言模型技术_推理优化 堆叠 Transformer 层来创建大型模型可以带来更好的准确性、少样本学习能力&#xff0c;甚至在各种语言任务上具有接近人类的涌现能力。 这些基础模型的训练成本很高&#xff0c;并且在推理过程中可能会占用大量内存和计算资源&#xff08;经常性成…

C++:反向迭代器-reverse_iterator

目录 1.关于反向迭代器 2.反向迭代器的成员函数 1.构造 2.base 3.operator* 4.operator 5.operator-- 6.operator-> 7.operator[] 3.反向迭代器的模拟实现 小结 1.关于反向迭代器 在C中&#xff0c;可以使用反向迭代器来逆序遍历容器中的元素。反向迭代器是通过…

链表的中间结点,简单的快慢指针问题

总结 struct ListNode* middleNode(struct ListNode* head) {struct ListNode*fasthead;struct ListNode*slowhead;while( fast && fast->next)//结束条件{slowslow->next;fastfast->next->next;}return slow; }

组件冲突、data函数、组件通信

文章目录 1.组件的三大组成部分 - 注意点说明2.组件的样式冲突&#xff08;用 scoped 解决&#xff09;3.data是一个函数4.组件通信1.什么是组件通信&#xff1f;2.不同的组件关系 和 组件通信方案分类 5.prop详解prop 校验①类型校验②完整写法&#xff08;类型&#xff0c;非…

面试项目问题

1. 你们这个项目多少人在做?人员分布是怎样的?做了多长时间? 我们项目组一共十个人&#xff0c;包括四个后端开发人员、两个前端开发人员、两个测试人员和两个产品经理。 从需求分析、设计、开发到测试上线到最后的维护阶段&#xff0c;整个项目的周期大概是六个月左右。 …

REVIT二次开发设置门垛高度

步骤1 步骤2 步骤3 using System; using System.Collections.Generic; using System.Linq; using System

Redis 持久化详解:RDB 与 AOF 的配置、触发机制和实际测试

什么是持久化&#xff1f; 就是 Redis 将内存数据持久化到硬盘&#xff0c;避免从数据库恢复数据。之所以避免从数据库恢复数据是因为后端数据通常有性能瓶颈&#xff0c;大量数据从数据库恢复可能会给数据库造成巨大压力。 Redis 持久化通常有 RDB 和 AOF 两种方式&#xff…

《开始使用PyQT》 第01章 PyQT入门 02 安装Python3和PyQT6

02 安装Python3和PyQT6 《开始使用PyQT》 第01章 PyQT入门 02 安装Python3和PyQT6 So that all readers are on the same page, let’s begin by installing or updating your version of Python. 为了让所有读者都能理解&#xff0c;让我们从安装或更新 Python 版本开始。 …