java并发编程Future类详解

article/2025/11/7 12:31:04

作用和举例

在这里插入图片描述
future类的作用就是为了调用其他线程完成好后的结果,再返回到当前线程中,如上图举例:

小王自己是主线程,叫外卖等于使用future类,叫好外卖后小王就接着干自己的事去了,当外卖到了的时候,future.get获取,继续做接下来的事情

但要注意的是当还没获取外卖的时候,主线程中用餐这一步是卡住的

另一个实际项目中的例子:
在进行传统的 RPC(远程调用)时,同步调用 RPC 是一段耗时的过程。当客户端发出 RPC请求,服务端完成请求处理需要很长的一段时间才会返回,这个过程中客户端一直在等待,直到 数据返回随后再进行其他任务的处理。现有一个 Client 同步对三个 Server 分别进行一次 RPC调用。

在这里插入图片描述

假设一次远程调用的时间为 500ms,则一个 Client 同步对三个 Server 分别进行一次 RPC 调 用的总时间,需要耗费 1500ms。如果节省这个总时间呢,可以使用 Future 模式对其进行改造,将同步的 RPC 调用改为异步并发的 RPC 调用,一个 Client 异步并发对三个 Server 分别进行一次 RPC 调用

在这里插入图片描述

JDK中的Future实现

结构如下
在这里插入图片描述
future接口定义的方法:

  • cancel():如果等太久,你可以直接取消这个任务
  • isCancelled():任务是不是已经取消了
  • isDone():任务是不是已经完成了
  • get():有2个get()方法,不带参数的表示无穷等待,或者你可以只等待给定时间

使用:

	//异步操作 可以用一个线程池ExecutorService executor = Executors.newFixedThreadPool(1);//执行FutureTask,相当于上例中的 client.request("name") 发送请求//在这里开启线程进行RealData的call()执行Future<String> future = executor.submit(new RealData("name"));System.out.println("请求完毕,数据准备中");try {//这里依然可以做额外的数据操作,这里使用sleep代替其他业务逻辑的处理Thread.sleep(2000);} catch (InterruptedException e) {}//如果此时call()方法没有执行完成,则依然会等待System.out.println("数据 = " + future.get());

executor.submit()里传线程类
在这里插入图片描述
走这里看源码
在这里插入图片描述

	public <T> Future<T> submit(Callable<T> task) {if (task == null) throw new NullPointerException();// 根据Callable对象,创建一个RunnableFuture,这里其实就是FutureTaskRunnableFuture<T> ftask = newTaskFor(task);//将ftask推送到线程池//在新线程中执行的,就是run()方法,在下面的代码中有给出execute(ftask);//返回这个Future,将来通过这个Future就可以得到执行的结果return ftask;}protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {return new FutureTask<T>(callable);}

RunnableFuture其实就是FutureTask
在这里插入图片描述

FutureTask作为一个线程单独执行时,会将结果保存到outcome中,并设置任务的状态,下面是FutureTask的run()方法:
在这里插入图片描述
Future类最关键的get实现
在这里插入图片描述

FutureTask源码,关键在于awaitDone()方法里有park()阻塞了线程,成功后返回outcome
在这里插入图片描述
outcome:保存的就是最终的计算结果,get/set里都有它
在这里插入图片描述
在这里插入图片描述

Future模式的高阶版本—— CompletableFuture

Future模式虽然好用,但也有一个问题,那就是将任务提交给线程后,调用线程并不知道这个任务什么时候执行完,如果执行调用get()方法或者isDone()方法判断,可能会进行不必要的等待,那么系统的吞吐量很难提高。

CompletableFuture可以理解为Future模式的升级版本,它最大的作用是提供了一个回调机制,可以在任务完成后,自动回调一些后续的处理,这样,整个程序可以把“结果等待”完全给移除了。

例子:
在这里插入图片描述

它可以在Future执行成功后,自动回调进行下一步的操作,因此整个程序不会有任何阻塞的地方(也就是说你不用去到处等待Future的执行,而是让Future执行成功后,自动来告诉你)。

CompletableFuture之所有会有那么神奇的功能,完全得益于AsyncSupply类(由上述代码中的supplyAsync()方法创建)
在这里插入图片描述
在这里插入图片描述

作为Runnable,看他run的方法
在这里插入图片描述
d.completeValue(f.get())就是你要执行的异步方法,结果会被保存下来,放到d.result字段中

d.postComplete()会调用后续一系列操作,在这个后续处理中,就会调用thenAccept()中的消费者,相当于Future完成后的通知

代码如下:

   final void postComplete() {//省略部分代码,重点在tryFire()里//在tryFire()里,真正触发了后续的调用,也就是thenAccept()中的部分f = (d = h.tryFire(NESTED)) == null ? this : d;}}}

实现自己的Future模式

还是用敖丙的例子,主要实现类如下:
在这里插入图片描述

先定义接口

public interface Data {public String getResult ();
}

实现自己的future类:

public class FutureData implements Data {// 内部需要维护RealDataprotected RealData realdata = null;          protected boolean isReady = false;public synchronized void setRealData(RealData realdata) {if (isReady) { return;}this.realdata = realdata;isReady = true;//RealData已经被注入,通知getResult()notifyAll();                            			}//会等待RealData构造完成public synchronized String getResult() {        	while (!isReady) {try {//一直等待,直到RealData被注入wait();                        			} catch (InterruptedException e) {}}//真正需要的数据从RealData获取return realdata.result;                    		}
}

关键在于isReady这个布尔,while (!isReady)作为自旋锁,想要获取这个future的结果,他会一直等待,直到RealData被注入

RealData类:

public class RealData implements Data {protected final String result;public RealData(String para) {StringBuffer sb=new StringBuffer();//假设这里很慢很慢,构造RealData不是一个容易的事result =sb.toString();}public String getResult() {return result;}
}

Client类,目的是将RealData注入到FutureData

public class Client {//这是一个异步方法,返回的Data接口是一个Futurepublic Data request(final String queryStr) {final FutureData future = new FutureData();new Thread() {                                      public void run() {                    	// RealData的构建很慢,所以在单独的线程中进行RealData realdata = new RealData(queryStr);//setRealData()的时候会notify()等待在这个future上的对象future.setRealData(realdata);}                                               }.start();// FutureData会被立即返回,不会等待RealData被构造完return future;                        		}
}

mian方法通过data.getResult()拿数据

public static void main(String[] args) {Client client = new Client();//这里会立即返回,因为得到的是FutureData而不是RealDataData data = client.request("name");System.out.println("请求完毕");try {//这里可以用一个sleep代替了对其他业务逻辑的处理//在处理这些业务逻辑的过程中,RealData被创建,从而充分利用了等待时间Thread.sleep(2000);} catch (InterruptedException e) {}//使用真实的数据,如果到这里数据还没有准备好,getResult()会等待数据准备完,再返回System.out.println("数据 = " + data.getResult());
}

自己实现就拿wait简单处理,future类使用park阻塞

总结

Future 模式的核心思想是异步调用,有点类似于异步的 Ajax 请求。当调用某个耗时方法时, 可以不急于立刻获取结果,可以让被调用者立刻返回一个契约(或异步任务), 并且将耗时的方法放到另外线程执行,后续凭契约再去获取异步执行的结果。

在具体的实现上,Future 模式和异步回调模式既有区别,又有联系。Java 的 Future 模式实现,没有实现异步回调模式,仍然需要主动去获取耗时任务的结果;而 Java 8 中的 CompletableFuture,实现了异步回调模式。

参考:
JAVA Future类详解

更详细的可以看这一遍
Future模式与异步回调模式


http://chatgpt.dhexx.cn/article/sbaLZ2hd.shtml

相关文章

Java并发工具CountDownLatch使用详解

本文目录 1、使用场景2、使用介绍3、使用案例4、 Thread.join()和CountDownLatch的区别 1、使用场景 通过使用 CountDownLatch可以使当前线程阻塞&#xff0c;等待其他线程完成给定任务。可以类比旅游团导游要等待所有的游客到齐后才能去下一个景点。 CountDownLatch 主要应用…

Java 并发编程(一):简介

这篇文章的标题原本叫做——Java 并发编程(一)&#xff1a;简介&#xff0c;作者名叫小二。但我在接到投稿时觉得这标题不够新颖&#xff0c;不够吸引读者的眼球&#xff0c;就在发文的时候强行修改了标题&#xff08;也不咋滴&#xff09;。 小二是一名 Java 程序员&#xff…

Java并发编程的艺术下载

本书简介 并发编程领域的扛鼎之作&#xff0c;作者是阿里和1号店的资深Java技术专家&#xff0c;对并发编程有非常深入的研究&#xff0c;《Java并发编程的艺术》是他们多年一线开发经验的结晶。本书的部分内容在出版早期发表在Java并发编程网和InfoQ等技术社区&#xff0c;得…

Java并发工具之Semaphore

一、简介 摘自《Java并发编程的艺术》一书 Semaphore&#xff08;信号量&#xff09;是用来控制同时访问特定资源的线程数量&#xff0c;它通过协调各个线程&#xff0c;以保证合理的使用公共资源。 Semaphore一般用于流量的控制&#xff0c;特别是公共资源有限的应用场景。例…

Java 并发编程实战-创建和执行任务的最佳实践

若无法通过并行流实现并发&#xff0c;则必须创建并运行自己的任务。运行任务的理想Java 8方法就是CompletableFuture。 Java并发的历史始于非常原始和有问题的机制&#xff0c;并且充满各种尝试的优化。本文将展示一个规范形式&#xff0c;表示创建和运行任务的最简单&#x…

java并发-java并发大师

文章目录 java并发大师James GoslingDoug Lea 参考 java并发大师 聊聊java&#xff08;十&#xff09;Java并发大师Brain Goetz和Doug Lea 的中英文博客文章地址 参考URL: https://blog.csdn.net/weixin_33963594/article/details/92481739 James Gosling 技术大牛收割机&am…

java并发编程之 并发问题及解决方法

一、并发问题的根源 首先&#xff0c;我们要知道并发要解决的是什么问题&#xff1f;并发要解决的是单进程情况下硬件资源无法充分利用的问题。而造成这一问题的主要原因是CPU-内存-磁盘三者之间速度差异实在太大。如果将CPU的速度比作火箭的速度&#xff0c;那么内存的速度就…

『图解Java并发编程系列』10张图告诉你Java并发多线程那些破事

目录 线程安全问题 活跃性问题 性能问题 有态度的总结 头发很多的程序员&#xff1a;『师父&#xff0c;这个批量处理接口太慢了&#xff0c;有什么办法可以优化&#xff1f;』架构师&#xff1a;『试试使用多线程优化』第二天头发很多的程序员&#xff1a;『师父&#xff…

Java基础-并发篇

3.1. JAVA 并发知识库 3.2. JAVA 线程实现/创建方式 3.2.1. 继承 Thread 类 ​ Thread 类本质上是实现了 Runnable 接口的一个实例&#xff0c;代表一个线程的实例。启动线程的唯一方 法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法&#xff0c;它将…

java并发总结

一、并发基础 ㅤ 1、进程与线程 ㅤ 进程 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 I…

pytorch 图片分类,python 图片分类,resnet18 图片分类

pytorch 图片分类&#xff0c;python 图片分类&#xff0c;resnet18 图片分类&#xff0c;深度学习 图片分类 pytorch版本&#xff1a;1.5.0cu101 全部源码&#xff0c;可以直接运行。 下载地址&#xff1a;https://download.csdn.net/download/TangLingBo/12598435 网络是…

深度学习图片分类实战学习

开始记录学习深度学习的点点滴滴 深度学习图片分类实战学习 前言一、深度学习二、使用步骤1. 自建网络模型2. 进行深度学习的学习迁移 注意事项 前言 随着人工智能的不断发展&#xff0c;这门技术也越来越重要&#xff0c;很多人都开启了学习人工智能&#xff0c;本人开始记录…

关于图片的多标签分类(1)

最近还在处理人脸附件&#xff08;眼镜&#xff0c;刘海&#xff0c;口罩&#xff0c;帽子&#xff09;的multi-label分类。给自己普及一下常识性问题&#xff1a; 1&#xff09;什么是multi-label分类&#xff1f; multi-label分类&#xff0c;常见一张图片中可以存在多个目…

svm实现图片分类(python)

目录 前言 knn vs. svm svm & linear classifier bias trick loss function regularization optimization 代码主体 导入数据及预处理 svm计算loss_function和梯度 验证梯度公式是否正确 比较运行时间 svm训练及预测&#xff0c;结果可视化 通过corss-validat…

图片分类-python

目的&#xff1a;做一个简易的图片分类。 使用到的算法&#xff1a;hog、surfsvm 图片集&#xff1a;cifar-10、cifar-100、stl-10、自制图片集 分类完整代码链接 使用说明&#xff1a; 1.cifar-10、cifar-100和stl-10直接解压 2.自制图片集文件夹结构&#xff1a; ├…

CNN图片分类

最近在阅读一些AI项目&#xff0c;写入markdown&#xff0c;持续更新&#xff0c;算是之后也能回想起做法 项目 https://github.com/calssion/Fun_AI image classify(图片分类) CNN classify dogs and cats(猫狗二分类) Tutorial(教程):https://developers.google.com/mach…

深度学习之图像分类

第一篇CSDN文章&#xff0c;写的不好&#xff0c;还请各位大佬指正。万事开头难&#xff0c;千里之行始于足下&#xff01; 1.什么是图像分类 图像分类&#xff0c;核心是从给定的分类集合中给图像分配一个标签的任务。实际上&#xff0c;这意味着我们的任务是分析一个输入图…

关于图像分类

https://www.zhihu.com/question/57075015/answer/194397802https://www.zhihu.com/question/57075015/answer/194397802 先定义一下图像分类&#xff0c;一般而言&#xff0c;图像分类分为通用类别分类以及细粒度图像分类 那什么是通用类别以及细粒度类别呢&#xff1f;这里…

(一)图像分类任务介绍 Image Classification

目录 一、什么是图像分类任务&#xff1f;它有哪些应用场景&#xff1f; 二、图像分类任务的难点&#xff1f; 三、基于规则的方法是否可行&#xff1f; 四、什么是数据驱动的图像分类范式&#xff1f; 数据集构建 分类器设计与学习 分类器决策 五、常用的分类任务评价指…

图像分类的数据集

图像分类的数据集 1. MNIST2. Fashion-MNIST3.CIFAR-10和CIFAR-1004. Caltech 1015. ImageNet5.1 ImageNet是什么&#xff1f;5.2 ILSVRC 6. 各个数据集上的最新进展其他参考资料 1. MNIST MNIST数据集的一个样例 一般机器学习框架都使用MNIST作为入门&#xff0c;就像"He…