JAVA Future类详解及Thread线程是如何运行Future类的

news2024/11/24 1:38:00

一、Future基本介绍

        Future(java.util.concurrent Interface Future<V>)表示异步计算的结果。Future接口提供了检查计算是否完成、检查计算是否被取消、等待计算完成并获取计算结果等方法。

        在并发编程中,我们经常用到非阻塞的模型,但继承thread类和实现runnable接口,都无法保证获取到之前的执行结果。而通过实现Callback接口,并用Future可以来接收多线程的执行结果。

        Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。

二、Future使用方法

public static void main(String[] args) throws ExecutionException, InterruptedException {
    Callable call = new Callable<String>(){
        @Override
        public String call() throws Exception {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "我被调用";
        }
    };
    FutureTask<String> future = new FutureTask<String>(call);
    new Thread(future).start();
    System.out.println(future.get());
}

        返回结果“我被调用” 

        接下来我们就围绕这这段代码看看整体的运行流程。

        我们这里主要关注的类是Callable FutureTask两个类

三、Callable类

         Callable是个支持泛型的函数式接口,里面有个call()方法

四、FutureTask继承体系

        RunnableFuture是个组合接口,继承了Future和Runnable两个接口,FutureTask实现了RunnableFuture接口,所以FutureTask拥有Future和Runnable两个接口的功能,我们知道Runnable接口是个函数式接口,里面只有一个run方法,我们重点看下Future这个类

五、Future类接口说明

/**
 * 方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,
 * 如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false
 * 注意:mayInterruptIfRunning不一定会影响取消,要看具体实现,concurrent包里面部分类是不受该参数影响的,如CompletableFuture
*/
boolean cancel(boolean mayInterruptIfRunning);

/**
 * 任务是否已经取消
 */
boolean isCancelled();

/**
 * 任务是否已经完成
 */
boolean isDone();

/**
 * 获取任务返回值,未执行完成则会阻塞等待结果
 */
V get() throws InterruptedException, ExecutionException;

/**
 * 指定超时时间,规定时间未获取结果则抛出TimeoutException
 */
V get(long timeout, TimeUnit unit)
	throws InterruptedException, ExecutionException, TimeoutException;

六、FutureTask的主要实现

        我们知道我们调用了Thread的start()方法之后线程进入就绪状态,在线程获取运行资源之后会调用run()方法,所以我们就从这里入手,看看FutureTask的run()方法:

public void run() {
	if (state != NEW ||
		!RUNNER.compareAndSet(this, null, Thread.currentThread()))
		return;
	try {
	    // 这里是初始化我们传入的callable对象
		Callable<V> c = callable;
		if (c != null && state == NEW) {
			V result;
			boolean ran;
			try {
				// 调用callable的call方法并获取返回结果
				result = c.call();
				ran = true;
			} catch (Throwable ex) {
				result = null;
				ran = false;
				setException(ex);
			}
			if (ran)
				// 成功获取之后封装返回结果
				set(result);
		}
	} finally {
		// runner must be non-null until state is settled to
		// prevent concurrent calls to run()
		runner = null;
		// state must be re-read after nulling runner to prevent
		// leaked interrupts
		int s = state;
		if (s >= INTERRUPTING)
			handlePossibleCancellationInterrupt(s);
	}
}

        由上面的代码我们可以看到run()方法在执行的时候调用了我们传入的Callable对象的call()方法,并在成功执行后获取返回结果并对返回结果做封装,接下来我们看看封装返回结果的set()方法:

protected void set(V v) {
	if (STATE.compareAndSet(this, NEW, COMPLETING)) {
        // 将返回结果传到outcome参数中
		outcome = v;
		STATE.setRelease(this, NORMAL); // final state
		finishCompletion();
	}
}

        FutureTask将Callable的call()方法的运行的返回结果传到outcome参数中,至此这个调用过程也结束了,我们看看父类Future的get方法的实现是如何获取返回参数的:

public V get() throws InterruptedException, ExecutionException {
	int s = state;
	if (s <= COMPLETING)
		s = awaitDone(false, 0L);
	return report(s);
}

        跟进去report()方法:

private V report(int s) throws ExecutionException {
	Object x = outcome;
	if (s == NORMAL)
		// 返回outcome对象
		return (V)x;
	if (s >= CANCELLED)
		throw new CancellationException();
	throw new ExecutionException((Throwable)x);
}

        至此,我们就跟完了整个调用流程了。

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

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

相关文章

基于 SpringBoot+Vue+Java 的留守儿童系统的研究与实现(附源码,教程)

文章目录 1.研究背景2. 技术栈3.系统分析4系统设计5系统的详细设计与实现5.1系统功能模块5.2管理员功能模块 1.研究背景 以往的留守儿童爱心的管理&#xff0c;一般都是纸质文件来管理留守儿童爱心信息&#xff0c;传统的管理方式已经无法满足现代人们的需求&#xff1b;使用留…

[激光原理与应用-69]:激光器-器件 - 三极管

第1章 什么是三级管 三极管&#xff0c;全称应为半导体三极管&#xff0c;也称双极型晶体管、晶体三极管&#xff0c;是一种控制电流的半导体器件。其作用是把微弱电流信号放大成幅度值较大的电流信号&#xff0c;也用作无触点开关。电流信号经过电阻后&#xff0c;就变成了电压…

ARM嵌入式编译器编译优化选项 -O

Arm嵌入式编译器可以执行一些优化来减少代码量并提高应用程序的性能。不同的优化级别有不同的优化目标&#xff0c;不仅如此&#xff0c;针对某个目标进行优化会对其他目标产生影响。比如想减小生成的代码量&#xff0c;势必会影响到该代码的性能。所以优化级别总是这些不同目标…

Python中 re.findAll()、re.sub()、set()的使用

1. re.findall() re.findall()&#xff1a;函数返回包含所有匹配项的列表。返回string中所有与pattern相匹配的全部字串&#xff0c;返回形式为list / 数组。 由函数原型代码可知&#xff0c;findall() 函数存在三个参数&#xff1a; 1. pattern&#xff1a;正则表达式中的 ‘模…

RK3568平台开发系列讲解(驱动基础篇)IO 模型的分类

🚀返回专栏总目录 文章目录 一、阻塞 IO二、非阻塞 IO三、IO 多路复用四、信号驱动五、异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将针对IO模型进行分类。 假设有这样一个场景,从磁盘中循环读取 100M 的数据并处理,磁盘读取 100M 需要花费 20 秒的…

HR真的会嫌弃跳槽频繁的测试人员吗?

我们都知道&#xff1a;“跳槽≠涨薪”&#xff0c;但是对于测试人来说&#xff0c;跳槽绝哔能和升职加薪画上等号啊。 所以&#xff0c;有很多测试人在一家公司常常待不到1年&#xff0c;就另觅新东家&#xff0c;来借此达成升职加薪的目的。 有人提出质疑&#xff1a;为什么测…

【老王读SpringMVC-2】url 与 controller method 的映射关系注册

上文提到&#xff0c;如果我们自己要实现 spring mvc 框架的话&#xff0c;大致需要实现如下功能&#xff1a; 0、将 url 与 Controller method 的对应关系进行注册1、通过请求的 url 找到 Controller method (即 url 与 Controller method 的映射)2、将请求参数进行绑定&…

【python中的迭代器了解一下?】

基本说明 在 Python 中&#xff0c;迭代器是一种用于遍历可迭代对象&#xff08;如列表、元组、字符串等&#xff09;的方式。迭代器提供了一种简洁而有效的方法来遍历序列&#xff0c;而不需要创建临时变量或使用循环语句。 在 Python 中&#xff0c;迭代器是一个实现了 __i…

没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统)

环境: DELL7080台式机 Ubuntu20.04 两块硬盘 问题描述: 没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统) 解决方案: 一、下载镜像文件 1.上线自行下载安装镜像文件 二、分区 1.win10下磁盘管理压缩2个分区一个10G左右制作安装盘,一个几百G安装系统使用 10…

【Android入门到项目实战-- 7.1】—— 如何使用通知?

目录 一、创建通知的步骤 1、创建一个NotificationManager实例 2、使用一个Builder构造器来创建Notification对象 3、设置标题、文字、时间和图标等信息 4、显示通知 二、通知实例演示 三、实现通知的点击效果 1、PendingIntent 什么是PendingIntent&#xff1f; 如何使…

后台-husky提交代码规范使用

husky是一个git hook工具&#xff0c;可以帮助我们触发git提交的各个阶段&#xff1a;pre-commit、commit-msg、pre-push 1.如何使用husky呢&#xff1f; npx husky-init && npm installWindows安装不成功试试npx husky-init && npm install 2.git commit规范…

线索二叉树的前序遍历

线索二叉树原理 遍历二叉树的其实就是以一定规则将二叉树中的结点排列成一个线性序列&#xff0c;得到二叉树中结点的先序序列、中序序列或后序序列。这些线性序列中的每一个元素都有且仅有一个前驱结点和后继结点。 但是当我们希望得到二叉树中某一个结点的前驱或者后继结点时…

计算机组成原理---第 6 章总线系统

一、总线的概念和结构形态 总线的基本概念 ⑴概述 总线是构成计算机系统的互联机构&#xff0c;是多个系统功能部件之间进行数据传送的公共通路。 ⑵ 分类 总线的分类方式有很多&#xff1a;如被分为外部总线和内部总线、系统总线和非系统总线、片内总线和PCB板级总线、串行…

VS2022+opengl环境配置

glfw下载Download | GLFW glad下载https://glad.dav1d.de/ Freeglut下载 https://freeglut.sourceforge.net/index.php#download cmake下载 Download | CMake glfwFreeglut 用cmake配置Freeglut&#xff0c;生成vs工程项目&#xff0c;用vs2022编译项目&#xff0c;生成fr…

27.Spring的事务控制

目录 一、编程式事务控制相关对象。 &#xff08;1&#xff09;事务管理器。 &#xff08;2&#xff09;事务定义信息对象&#xff08;如隔离级别、传播行为&#xff09;。 &#xff08;3&#xff09;事务状态对象。 &#xff08;4&#xff09; 知识要点。 二、声明式事务…

基于STM32的开源简易示波器项目

目录 ​一、前言 二、硬件接线 三、信号的采集 四、代码配置 五、数据的处理 六、模拟正弦波输出 七、模拟噪声或三角波输出 八、显示函数与按键控制 ​一、前言 该项目是基于正点原子精英板制作的一个简易示波器&#xff0c;可以读取信号的频率和幅值&#xff0c;并可…

JetpackCompose从入门到实战学习笔记14

JetpackCompose从入门到实战学习笔记14——Coli的简单使用 1.简介&#xff1a; Coil 是一个 Android官方出的配合Jetpack的图片加载库&#xff0c;通过 Kotlin 协程的方式加载图片。 优点如下&#xff1a; 更快: Coil 在性能上有很多优化&#xff0c;包括内存缓存和磁盘缓存…

C/C++基础知识

专栏&#xff1a;C/C 个人主页&#xff1a; C/C基础知识 前言C关键字(C98)命名空间命名空间的定义正常的命名空间的定义如何使用命名空间 命名空间可以嵌套同一个工程中允许存在多个相同名称的命名空间&#xff0c;编译器最后会合成同一个命名空间中(一个工程中的.h文件和test.…

(数字图像处理MATLAB+Python)第七章图像锐化-第一、二节:图像锐化概述和微分算子

文章目录 一&#xff1a;图像边缘分析二&#xff1a;一阶微分算子&#xff08;1&#xff09;梯度算子A&#xff1a;定义B&#xff1a;边缘检测C&#xff1a;示例D&#xff1a;程序 &#xff08;2&#xff09;Robert算子A&#xff1a;定义B&#xff1a;示例C&#xff1a;程序 &a…

Tailscale: Please Restart the Tailscale Windows Service

之前用的好好的&#xff0c;最近重新升级了一下Tailscale后发现一直连不上。右击win10右下角的Tailscale图标&#xff0c;第一行显示&#xff1a;Please Restart the Tailscale Windows Service。 我查看了一下服务&#xff0c;发现Tailscale是自动的&#xff0c;这里的启动类…