future和CompletableFuture
future
什么是future
Future 类是并发编程中一个非常重要的工具。它主要用于表示一个异步计算的结果,允许你在计算完成后获取结果或处理异常。Java 的 Future 也常常与线程池(如 ExecutorService)结合使用,用来执行并行任务,并返回任务的执行结果。
Java 中的 Future 主要用于以下几个场景:
异步计算:当我们希望在不阻塞主线程的情况下执行任务,并能在稍后获取任务的结果时,可以使用 Future。
任务控制:通过 Future,我们可以检查任务是否完成,获取任务的执行结果,或者取消正在执行的任务。
避免阻塞:Future 允许我们在等待计算结果时,不会阻塞主线程。
future常见方法
在 Java 中,Future 类提供了几种常见的方法来管理异步任务的执行:
get():等待异步任务完成并获取结果,如果任务抛出异常,会重新抛出该异常。
get(long timeout, TimeUnit unit):带有超时限制的 get 方法,等待任务完成的最长时间,超时后抛出 TimeoutException。
cancel(boolean mayInterruptIfRunning):取消任务。如果任务已经开始执行,且 mayInterruptIfRunning 为 true,会中断任务。
isDone():检查任务是否已经完成。
isCancelled():检查任务是否已经被取消。
使用示例
get()简单的异步任务
使用 ExecutorService 提交任务,并通过 Future 获取任务的结果
import java.util.concurrent.*;public class FutureExample {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService executorService = Executors.newFixedThreadPool(1);// 提交一个异步任务Future<Integer> future = executorService.submit(() -> {// 模拟一些计算Thread.sleep(2000);return 42; // 返回结果});// 在任务完成之前执行其他操作System.out.println("Main thread is doing other work...");// 获取任务的结果,若任务未完成,则会阻塞直到任务完成Integer result = future.get(); // 阻塞直到任务完成System.out.println("Task result: " + result);executorService.shutdown();}
}
带超时的 get() 方法
Future 的 get(long timeout, TimeUnit unit) 方法允许我们为任务设置一个超时。如果在指定的时间内任务没有完成,会抛出 TimeoutException。
import java.util.concurrent.*;public class FutureTimeoutExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(1);// 提交一个任务Future<Integer> future = executorService.submit(() -> {Thread.sleep(5000); // 模拟长时间任务return 100;});try {// 设置超时,等待最多 3 秒Integer result = future.get(3, TimeUnit.SECONDS);System.out.println("Task result: " + result);} catch (TimeoutException e) {System.out.println("Task timed out!");future.cancel(true); // 取消任务} catch (InterruptedException | ExecutionException e) {System.out.println("An error occurred: " + e.getMessage());}executorService.shutdown();}
}
取消任务cancel(boolean mayInterruptIfRunning)
通过 future.cancel(true) 来取消任务。true 表示如果任务已经开始执行,允许中断任务。
import java.util.concurrent.*;public class FutureCancelExample {public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(1);// 提交一个长时间运行的任务Future<Integer> future = executorService.submit(() -> {Thread.sleep(5000);return 100;});// 让主线程等待 2 秒钟Thread.sleep(2000);// 取消任务boolean isCancelled = future.cancel(true);if (isCancelled) {System.out.println("Task was successfully cancelled.");} else {System.out.println("Task could not be cancelled.");}executorService.shutdown();}
}
批量任务处理与 isDone() 方法
在实际开发中,有时我们需要提交多个任务,并等待它们完成。可以使用 isDone() 来检查每个任务是否已完成。
import java.util.concurrent.*;public class FutureBatchExample {public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(3);// 提交多个任务Future<Integer> future1 = executorService.submit(() -> {Thread.sleep(1000);return 10;});Future<Integer> future2 = executorService.submit(() -> {Thread.sleep(2000);return 20;});Future<Integer> future3 = executorService.submit(() -> {Thread.sleep(3000);return 30;});// 检查任务是否完成while (!future1.isDone() || !future2.isDone() || !future3.isDone()) {System.out.println("Waiting for tasks to complete...");Thread.sleep(500);}System.out.println("Task 1 result: " + future1.get());System.out.println("Task 2 result: " + future2.get());System.out.println("Task 3 result: " + future3.get());executorService.shutdown();}
}
CompletableFuture
什么是CompletableFuture
CompletableFuture 是 Java 8 引入的一个类,位于 java.util.concurrent 包中。它是 Future 类的一个增强版本,用于处理异步编程。与 Future 类不同,CompletableFuture 不仅支持基本的异步任务执行和结果获取,还提供了更多的功能,允许任务的组合、回调的注册、异常处理以及支持非阻塞地执行多个任务。
CompletableFuture和future的区别
| 特性 | Future | CompletableFuture |
|---|---|---|
| 异步计算结果的获取 | 通过 get() 方法,获取结果时会阻塞当前线程。 | 支持非阻塞的异步计算,使用 thenApply() 等方法继续处理结果。 |
| 任务组合 | 不支持任务的组合,无法在多个任务完成后做进一步操作。 | 支持任务的组合,提供 thenApply(), thenCombine(), allOf() 等方法来组合多个异步任务。 |
| 异常处理 | 如果任务执行出现异常,可以通过 get() 抛出异常,但没有方便的回调处理机制。 | 支持更丰富的异常处理,通过 handle(), exceptionally() 等方法处理异常。 |
| 任务手动完成 | 不支持手动完成任务。 | 可以手动完成任务,使用 complete() 或 completeExceptionally() 来控制任务的完成。 |
| 响应式编程 | 仅支持简单的异步结果获取。 | 支持响应式编程,能够注册多个回调处理器来响应任务的状态变化 |
CompletableFuture的常用方法
supplyAsync():异步执行一个返回结果的任务。
runAsync():异步执行一个没有返回结果的任务。
thenApply():任务完成后,基于结果执行一个转换操作。
thenAccept():任务完成后,基于结果执行一个操作,但不返回结果。
thenCombine():当两个任务都完成时,结合两个任务的结果。
exceptionally():处理异步任务的异常。
allOf():等待多个任务同时完成。
anyOf():等待多个任务中任意一个完成。
CompletableFuture使用案例
基本的异步计算
使用 supplyAsync() 提交了一个异步任务,主线程通过 get() 等待异步任务的完成并获取结果。
import java.util.concurrent.*;public class CompletableFutureExample {public static void main(String[] args) throws InterruptedException, ExecutionException {// 使用 supplyAsync 异步执行任务CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 模拟一个长时间的计算try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }return 42; // 返回结果});// 获取计算结果(会阻塞直到结果完成)Integer result = future.get();System.out.println("Task result: " + result);}
}
任务的组合
通过 thenApply() 和 thenCombine() 等方法,我们可以将多个异步任务组合在一起,完成更复杂的计算。
import java.util.concurrent.*;public class CompletableFutureCombinationExample {public static void main(String[] args) throws InterruptedException, ExecutionException {CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);// thenCombine() 用于将两个异步任务的结果合并CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (x, y) -> x + y);// 获取合并结果Integer result = combinedFuture.get();System.out.println("Combined result: " + result); // 输出 30}
}
异常处理
CompletableFuture 提供了更好的异常处理机制,可以通过 exceptionally() 来处理任务中的异常。
import java.util.concurrent.*;public class CompletableFutureExceptionExample {public static void main(String[] args) throws InterruptedException, ExecutionException {CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {if (true) {throw new RuntimeException("Something went wrong!");}return 42;});// 使用 exceptionally() 处理异常CompletableFuture<Integer> handledFuture = future.exceptionally(ex -> {System.out.println("Handling exception: " + ex.getMessage());return 0; // 异常处理后返回默认值});Integer result = handledFuture.get();System.out.println("Task result: " + result); // 输出 "Task result: 0"}
}
等待多个任务
通过 allOf() 方法,我们可以等待多个异步任务全部完成,然后处理它们的结果。
import java.util.concurrent.*;public class CompletableFutureAllOfExample {public static void main(String[] args) throws InterruptedException, ExecutionException {CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> 30);// 等待所有任务完成CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);// 等待所有任务完成后获取结果allOf.get(); // 阻塞,直到所有任务完成// 获取每个任务的结果System.out.println("Result of future1: " + future1.get());System.out.println("Result of future2: " + future2.get());System.out.println("Result of future3: " + future3.get());}
}
响应式编程
CompletableFuture 支持更为灵活的异步执行流,可以在任务完成后注册回调处理。
import java.util.concurrent.*;public class CompletableFutureCallbackExample {public static void main(String[] args) {CompletableFuture.supplyAsync(() -> {return 42;}).thenApply(result -> {System.out.println("Task result: " + result);return result * 2; // 处理任务结果}).thenAccept(finalResult -> {System.out.println("Final result: " + finalResult); // 输出最终结果});}
}
那么是否是CompletableFuture能完全替代Future
可以的,可以理解为CompletableFuture是Future的增强版本,就像Springboot能完全替代SpringMVC一样
CompletableFuture 完全可以替代 Future,因为它提供了 Future 的所有功能,并增加了更多强大的特性,如任务组合、异常处理、回调等。
对于复杂的异步操作和任务链式调用,CompletableFuture 是更好的选择,它使得异步编程更加灵活和简洁。
对于简单的任务执行和结果获取,如果没有任务组合、回调和异常处理的需求,Future 仍然是一个简单有效的选择。
总结来说,CompletableFuture 是更现代和强大的异步工具,Future 仍然可以在某些简单场景下使用,但大多数情况可以考虑使用 CompletableFuture 来简化代码并提高效率。
Future用来接收excutorservice执行的线程池,而Completable底层也是执行的线程池,使用默认线程池 ForkJoinPool.commonPool(),且可以更改为自定义的线程池,所以和Futre并没什么实质上的区别,只是一个增强版
相关文章:
future和CompletableFuture
future 什么是future Future 类是并发编程中一个非常重要的工具。它主要用于表示一个异步计算的结果,允许你在计算完成后获取结果或处理异常。Java 的 Future 也常常与线程池(如 ExecutorService)结合使用,用来执行并行任务&…...
如何通过深度学习提升大分辨率图像预测准确率?
随着科技的不断进步,图像处理在各个领域的应用日益广泛,特别是在医疗影像、卫星遥感、自动驾驶、安防监控等领域中,大分辨率图像的使用已经成为了一项不可或缺的技术。然而,大分辨率图像带来了巨大的计算和存储压力,同…...
【机器学习】机器学习的基本分类-半监督学习-Ladder Networks
Ladder Networks 是一种半监督学习模型,通过将无监督学习与监督学习相结合,在标记数据较少的情况下实现高效的学习。它最初由 A. Rasmus 等人在 2015 年提出,特别适合深度学习任务,如图像分类或自然语言处理。 核心思想 Ladder N…...
[react]小技巧, ts如何声明点击事件的类型
很简单, 鼠标放到事件上面就行了 如果想知道点击的是什么元素 ,打印他的nodename就行了 不过得断言为html元素才行 const handleClick (e: React.MouseEvent<HTMLDivElement, MouseEvent>) > {console.log(current, (e.target as HTMLElement).nodeName);}; 为什么…...
智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之9 重新开始 之2
本文要点 对程序设计而言:前者基于一个自上而下的 分类体系--(生物遗传基因),后者者需要一个收集差异的自下而上的差异继承路径--(系统继承源流) 就是 广义和狭义 分类学。 共性对齐 和 差异收集 正是两者…...
【从零开始】11. LLaMA-Factory 微调 Qwen 模型(番外篇)
书接上回,在完成了 RAGChecker 测试后,离 RAG 应用真正发布还差最后一步 - 基础信息指令微调。考虑到模型还是需要具备一定程度的“自我认知”,因此需要将公司信息“嵌入”到模型里面的。为此,我选择了 LLaMA-Factory(…...
WPF使用ContentControl控件实现区域导航,并使用Prism依赖注入优化
背景:使用ContentControl控件实现区域导航是有Mvvm框架的WPF都能使用的,不限于Prism 主要是将ContenControl控件的Content内容在ViewModel中切换成不同的用户控件 下面是MainViewModel: private object body;public object Body {get { retu…...
JavaWeb——MySQL-DML(1/3)-添加数据insert(DML 操作概述、INSERT 语句插入数据、语句演示、总结)
目录 DML 操作概述 INSERT 语句插入数据 INSERT 语句基础语法 INSERT 语句演示 注意事项 总结 DML 操作概述 DML 简介 DML(Data Manipulation Language)即数据操作语言,用于对数据库表中的数据进行增删改操作,包括添加数据&…...
经验证:将数据从索尼传输到Android的 4 种方法
概括 像Android Galaxy S20 这样的新型Android智能手机很酷,但除了将数据从索尼传输到Android之外。众所周知,旧的索尼手机上存储着大量的文件,因此将数据从旧的索尼手机传输到新的Android手机非常重要。为了解决这个问题,我们做…...
嵌入式应用实例→电子产品量产工具→UI界面的绘制和测试
前言 之前已经在博文https://blog.csdn.net/wenhao_ir/article/details/144747714中实现了用Freetype在LCD屏上绘制字符,本篇博文我们利用Freetype实现UI界面的绘制。 头文件include\ui.h的分析 头文件内的代码 #ifndef _UI_H #define _UI_H#include <common…...
如何删除 Docker 中的悬虚镜像?
在 Docker 中,悬虚镜像(Dangling Images)是指那些没有 标签 且没有被任何容器使用的镜像。这些镜像通常是由于构建过程中生成的中间层镜像或未正确清理的镜像残留。删除悬虚镜像可以释放磁盘空间并保持 Docker 环境的整洁。 1. 列出悬虚镜像…...
el-table树形懒加载展开改为点击行展开
思路:获取el-table中小箭头,然后调它的click事件! <el-tablerow-click"getOpenDetail":row-class-name"tableRowClassName">// 点击当前行展开节点getOpenDetail(row, column, event) {// 如果是叶子节点或点击的是…...
【Ubuntu】Ubuntu server 18.04 搭建Slurm并行计算环境(包含NFS)
Ubuntu server 18.04 搭建Slurm并行计算环境(包含NFS) 一、Munge 认证模块 1.1、安装 munge 主节点和子节点都安装munge #安装 sudo apt update && sudo apt install munge libmunge-dev#设置开机启动 sudo systemctl enable munge sudo syste…...
高并发场景下的秒杀系统架构设计与实现
引言 秒杀系统是一种高并发场景的典型应用,广泛存在于电商平台、抢票系统和促销活动中。秒杀活动的特点是短时间内吸引大量用户同时访问并尝试抢购商品,这对系统的高并发处理能力、稳定性和用户体验提出了极高的要求。 在秒杀系统中,常见的…...
搭建开源版Ceph分布式存储
系统:Rocky8.6 三台2H4G 三块10G的硬盘的虚拟机 node1 192.168.2.101 node2 192.168.2.102 node3 192.168.2.103 三台虚拟机环境准备 1、配置主机名和IP的映射关系 2、关闭selinux和firewalld防火墙 3、配置时间同步且所有节点chronyd服务开机自启 1、配置主机名和…...
QT----------多媒体
实现思路 多媒体模块功能概述: QT 的多媒体模块提供了丰富的功能,包括音频播放、录制、视频播放和摄像头操作等。 播放音频: 使用 QMediaPlayer 播放完整的音频文件。使用 QSoundEffect 播放简短的音效文件。 录制音频: 使用 QMe…...
选择器(结构伪类选择器,伪元素选择器),PxCook软件,盒子模型
结构为类选择器 伪元素选择器 PxCook 盒子模型 (内外边距,边框) 内外边距合并,塌陷问题 元素溢出 圆角 阴影: 模糊半径:越大越模糊,也就是越柔和 案例一:产品卡片 <!DOCTYPE html> <html lang&q…...
Vue2/Vue3 响应式原理对比指南
Vue2/Vue3 响应式原理对比指南 1. 基本实现原理 1.1 Vue2 响应式实现 (Object.defineProperty) // Vue2 响应式核心实现 function defineReactive(obj, key, val) {// 递归处理嵌套对象observe(val);const dep new Dep();Object.defineProperty(obj, key, {get() {// 依赖收…...
FastExcel:超越EasyExcel的新一代Excel处理工具
简介 FastExcel是由原EasyExcel作者在阿里巴巴宣布停止维护EasyExcel之后推出的升级版框架。它继承了EasyExcel的所有优点,并且在性能和功能上进行了显著的提升和创新。 FastExcel的特点 高性能读写:FastExcel专注于性能优化,能够高效处理…...
大模型系列17-RAGFlow搭建本地知识库
大模型系列17-RAGFlow搭建本地知识库 安装ollama安装open-wehui安装并运行ragflowRAG(检索、增强、生成)RAG是什么RAG三过程RAG问答系统构建步骤向量库构建检索模块生成模块 RAG解决LLM的痛点 使用ragflow访问ragflow配置ollama模型添加Embedding模型添加…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
