JavaFuture教程:手把手教你轻松获取异步计算结果
还在为Java异步计算结果的获取而烦恼吗?本文带你玩转Java中的Future!Future作为异步计算的代表,允许你提交任务后立即返回,无需阻塞等待结果,显著提升并发效率。文章将深入探讨Future的用法,包括如何使用`get()`方法阻塞或超时获取结果,如何利用`isDone()`方法非阻塞地检查任务状态,以及如何借助Guava的ListenableFuture实现回调机制,在任务完成后自动执行操作。此外,还将介绍`Future.cancel()`在资源释放和任务超时等场景下的应用,以及`FutureTask`的原理和使用。同时,本文也会对比Future与CompletableFuture的区别,助你选择更适合的异步编程方案,轻松应对各种并发场景。
Java中Future的主要作用是代表异步计算的结果,允许非阻塞地获取任务结果并提高并发效率。1.get()方法可阻塞式获取结果或设置超时;2.isDone()方法用于非阻塞检查任务是否完成;3.通过第三方库如Guava的ListenableFuture实现回调机制处理任务完成后自动执行的操作。此外,Future.cancel()可用于尝试取消任务,适用于资源释放、任务超时等场景。而FutureTask作为Runnable和Future的结合体,既能提交执行也能获取结果,其内部状态机管理任务生命周期。异常处理可通过get()中的try-catch捕获ExecutionException或使用回调机制处理。相比CompletableFuture,Future功能较为基础,后者提供链式调用、组合任务、更灵活的异常处理等功能,更适合复杂异步编程需求。

Java中Future的主要作用是代表异步计算的结果。它允许你在提交一个任务后,不必立即等待任务完成,而是先拿到一个Future对象,稍后再通过这个对象来获取计算结果。这在并发编程中非常有用,可以提高程序的响应速度和吞吐量。

Future提供了一种非阻塞的方式来获取异步任务的结果,避免了主线程被长时间阻塞的情况。你可以先执行其他的任务,然后在需要结果的时候再通过Future来获取。

解析异步计算结果的获取方式主要有三种:get() 方法、isDone() 方法和回调机制。

get() 方法:阻塞式获取结果,直到任务完成或超时
Future接口最常用的方法之一就是get()。当你调用future.get()时,如果任务还没有完成,调用线程会被阻塞,直到任务完成并返回结果,或者发生异常。get()方法还可以接受一个超时参数,如果在指定的时间内任务没有完成,会抛出TimeoutException。
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> {
Thread.sleep(2000); // 模拟耗时操作
return "任务完成";
});
try {
String result = future.get(3, TimeUnit.SECONDS); // 设置超时时间为3秒
System.out.println("结果: " + result);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}这个例子中,如果任务在3秒内没有完成,future.get()会抛出TimeoutException。
isDone() 方法:非阻塞式检查任务是否完成
isDone()方法允许你检查任务是否已经完成,而不会阻塞当前线程。你可以使用这个方法来定期检查任务的状态,并在任务完成后获取结果。
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> {
Thread.sleep(2000); // 模拟耗时操作
return "任务完成";
});
while (!future.isDone()) {
System.out.println("任务还在执行中...");
try {
Thread.sleep(500); // 每隔500毫秒检查一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
String result = future.get();
System.out.println("结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}回调机制:任务完成后自动执行回调函数
虽然Future本身没有直接提供回调机制,但可以通过一些库(如Guava的ListenableFuture)或者自己实现类似的功能。回调机制允许你在任务完成后自动执行一段代码,而不需要手动调用get()或者isDone()。
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
ExecutorService executor = Executors.newFixedThreadPool(10);
ListenableFuture<String> future = MoreExecutors.listeningDecorator(executor).submit(() -> {
Thread.sleep(2000); // 模拟耗时操作
return "任务完成";
});
Futures.addCallback(future, new FutureCallback<String>() {
@Override
public void onSuccess(String result) {
System.out.println("任务成功完成,结果: " + result);
}
@Override
public void onFailure(Throwable t) {
System.err.println("任务失败: " + t.getMessage());
}
}, MoreExecutors.directExecutor());
executor.shutdown();Guava的ListenableFuture提供了一个addCallback方法,可以在任务完成后执行onSuccess或onFailure回调。
Future.cancel()方法的作用和使用场景
Future.cancel() 方法用于尝试取消与 Future 关联的异步任务。它接收一个 boolean 类型的参数 mayInterruptIfRunning,决定是否允许中断正在运行的任务。
mayInterruptIfRunning = true: 尝试中断正在运行的任务。这通常通过调用任务执行线程的interrupt()方法来实现。然而,任务是否真正响应中断取决于任务本身的实现。mayInterruptIfRunning = false: 不允许中断正在运行的任务。如果任务尚未开始执行,则会被取消,否则任务会继续执行直到完成。
使用场景:
- 资源释放: 当不再需要异步任务的结果时,可以调用
cancel()方法来释放资源,避免不必要的计算。 - 任务超时: 如果异步任务执行时间过长,超过了预期的阈值,可以使用
cancel()方法来终止任务,防止资源被长时间占用。 - 程序退出: 在程序退出前,可以尝试取消所有未完成的异步任务,确保资源得到正确释放。
需要注意的是,cancel() 方法并不保证任务一定会被取消。如果任务已经完成或已经被取消,调用 cancel() 方法不会产生任何影响。此外,即使 mayInterruptIfRunning 为 true,任务也可能忽略中断信号,继续执行直到完成。因此,在设计异步任务时,应该考虑如何优雅地处理中断信号,确保任务能够及时停止并释放资源。
FutureTask的原理和使用
FutureTask 是一个可取消的异步计算任务,它实现了 RunnableFuture 接口,该接口继承自 Runnable 和 Future。 这意味着 FutureTask 既可以作为一个 Runnable 提交给 ExecutorService 执行,也可以作为一个 Future 来获取异步计算的结果。
原理:
FutureTask 内部维护了一个状态机,用于表示任务的不同状态:
- NEW: 任务创建后的初始状态。
- COMPLETING: 任务正在完成,正在设置结果或抛出异常。
- NORMAL: 任务正常完成,结果已设置。
- EXCEPTIONAL: 任务执行过程中发生异常。
- CANCELLED: 任务已被取消。
- INTERRUPTING: 任务正在中断。
- INTERRUPTED: 任务已被中断。
FutureTask 通过 run() 方法来执行任务。在 run() 方法中,它会调用任务的 call() 方法来执行实际的计算。计算结果会被保存,并将状态设置为 NORMAL 或 EXCEPTIONAL。
使用:
import java.util.concurrent.*;
public class FutureTaskExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<String> callable = () -> {
Thread.sleep(1000);
return "任务完成!";
};
FutureTask<String> futureTask = new FutureTask<>(callable);
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(futureTask);
System.out.println("任务提交...");
try {
String result = futureTask.get(); // 阻塞等待结果
System.out.println("结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}这个例子展示了如何使用 FutureTask 来执行一个异步任务。首先,创建一个 Callable 对象,表示要执行的任务。然后,创建一个 FutureTask 对象,并将 Callable 对象传递给它。接下来,将 FutureTask 对象提交给 ExecutorService 执行。最后,通过 futureTask.get() 方法来获取异步计算的结果。
如何处理Future中的异常
处理 Future 中的异常主要有两种方式:
- 在
get()方法中捕获异常:Future.get()方法会抛出InterruptedException和ExecutionException两种异常。InterruptedException表示当前线程在等待结果时被中断。ExecutionException表示在任务执行过程中发生了异常。可以通过try-catch块来捕获这些异常,并进行相应的处理。
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(() -> {
// 模拟异常
throw new RuntimeException("任务执行出错!");
});
try {
String result = future.get();
System.out.println("结果: " + result); // 这行代码不会被执行
} catch (InterruptedException e) {
System.err.println("线程被中断: " + e.getMessage());
} catch (ExecutionException e) {
System.err.println("任务执行出错: " + e.getCause().getMessage());
} finally {
executor.shutdown();
}在这个例子中,ExecutionException 的 getCause() 方法可以获取到原始的异常信息。
- 使用回调机制处理异常: 如前面提到的Guava的
ListenableFuture,可以在回调函数中处理异常。
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
ExecutorService executor = Executors.newFixedThreadPool(1);
ListenableFuture<String> future = MoreExecutors.listeningDecorator(executor).submit(() -> {
// 模拟异常
throw new RuntimeException("任务执行出错!");
});
Futures.addCallback(future, new FutureCallback<String>() {
@Override
public void onSuccess(String result) {
System.out.println("任务成功完成,结果: " + result); // 这行代码不会被执行
}
@Override
public void onFailure(Throwable t) {
System.err.println("任务失败: " + t.getMessage());
}
}, MoreExecutors.directExecutor());
executor.shutdown();使用回调机制可以更加灵活地处理异常,避免阻塞主线程。
Future与CompletableFuture的区别
Future 和 CompletableFuture 都是 Java 中用于处理异步计算结果的接口,但 CompletableFuture 是 Java 8 引入的,相比 Future 提供了更强大的功能和更灵活的编程模型。
- 更丰富的 API:
CompletableFuture提供了更多的 API,可以进行链式调用、组合多个异步任务、处理异常等。Future的 API 相对简单,只能获取结果和取消任务。 - 非阻塞性:
CompletableFuture提供了非阻塞的 API,可以在任务完成时自动触发回调函数,避免了Future.get()方法的阻塞等待。 - 组合性:
CompletableFuture可以将多个异步任务组合成一个新的异步任务,例如thenApply()、thenCompose()、thenCombine()等方法。 - 异常处理:
CompletableFuture提供了更强大的异常处理机制,可以使用exceptionally()、handle()等方法来处理异步任务中的异常。 - 更易于使用:
CompletableFuture的 API 设计更加友好,更容易使用和理解。
简单来说,CompletableFuture 是 Future 的增强版,提供了更多的功能和更灵活的编程模型,更适合构建复杂的异步应用。如果只需要简单的异步计算,可以使用 Future。如果需要更强大的功能和更灵活的编程模型,应该使用 CompletableFuture。
今天关于《JavaFuture教程:手把手教你轻松获取异步计算结果》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
Redis怎么用Docker部署?手把手教你超详细部署教程
- 上一篇
- Redis怎么用Docker部署?手把手教你超详细部署教程
- 下一篇
- Win10鼠标改成左手模式,超简单教程分享!
-
- 文章 · java教程 | 17分钟前 |
- Javatry-catch处理IO异常技巧
- 216浏览 收藏
-
- 文章 · java教程 | 8小时前 |
- Java栈溢出解决方法及状态分析
- 447浏览 收藏
-
- 文章 · java教程 | 9小时前 |
- Kotlin调用Java方法避免to歧义方法
- 121浏览 收藏
-
- 文章 · java教程 | 9小时前 |
- SpringBatchMaven运行与参数传递教程
- 347浏览 收藏
-
- 文章 · java教程 | 9小时前 |
- 公平锁如何避免线程饥饿问题
- 299浏览 收藏
-
- 文章 · java教程 | 9小时前 |
- Hibernate6.xCUBRID迁移指南
- 226浏览 收藏
-
- 文章 · java教程 | 10小时前 | 代码复用 类型安全 类型参数 extends关键字 Java泛型类
- Java泛型类定义与使用详解
- 480浏览 收藏
-
- 文章 · java教程 | 10小时前 |
- JavaCollectors数据聚合技巧解析
- 161浏览 收藏
-
- 文章 · java教程 | 11小时前 |
- LinkedHashMap删除操作对迭代顺序的影响分析
- 121浏览 收藏
-
- 文章 · java教程 | 11小时前 | java const final immutableobject staticfinal
- final与immutable区别详解
- 201浏览 收藏
-
- 文章 · java教程 | 11小时前 |
- JavaStreamgroupingBy使用教程
- 331浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3167次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3380次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3409次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4513次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3789次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览

