CompletableFuture使用案例
优化代码时,除了@Async注解,项目中如何使用多线程异步调用?
举个例子,去餐厅吃饭的时候。先点餐,厨师做菜,在厨师做菜的时候打游戏,然后根据厨师做的菜的口味去买矿泉水还是可乐。这样,厨师做菜并没有阻塞你打游戏,并且还是能接收到厨师任务的结果。与2个任务同步进行相比缩短了时间。
CompletableFuture
FutureTask也行,但不用
- 工具类
public class SmallTools {public static void sleepMillis(long millis){try {Thread.sleep(millis);}catch (InterruptedException exception){exception.printStackTrace();}}public static void printTimeAndThread(String tag){String result = new StringJoiner("\t|\t").add(String.valueOf(System.currentTimeMillis())).add(String.valueOf(Thread.currentThread().getId())).add(Thread.currentThread().getName()).add(tag).toString();System.out.println(result);}
}
- 测试1 说明CompletableFuture.supplyAsync会立即在后台线程池中异步执行 lambda 表达式,不需要显式调用。
public class Main {public static void main(String[] args) {SmallTools.printTimeAndThread("小白进入餐厅");SmallTools.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("厨师炒菜");SmallTools.sleepMillis(4000);SmallTools.printTimeAndThread("cf1线程结束");return "番茄炒蛋";});SmallTools.printTimeAndThread("小白开始打王者");SmallTools.sleepMillis(5000);SmallTools.printTimeAndThread("主线程结束");}
}
------
1715099888262 | 1 | main | 小白进入餐厅
1715099888262 | 1 | main | 小白点了 番茄炒蛋 + 一碗米饭
1715099888279 | 1 | main | 小白开始打王者
1715099888279 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师炒菜
1715099892285 | 9 | ForkJoinPool.commonPool-worker-9 | cf1线程结束
1715099893282 | 1 | main | 主线程结束
- 测试2 同时开启多个异步调用
public class Main {public static void main(String[] args) {SmallTools.printTimeAndThread("小白进入餐厅");SmallTools.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("厨师炒菜");SmallTools.sleepMillis(4000);SmallTools.printTimeAndThread("cf1线程结束");return "番茄炒蛋";});CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("服务员打饭");SmallTools.sleepMillis(4000);SmallTools.printTimeAndThread("cf2线程结束");return "饭";});SmallTools.printTimeAndThread("小白开始打王者");SmallTools.sleepMillis(5000);SmallTools.printTimeAndThread("主线程结束");}
}
------
1715100175308 | 1 | main | 小白进入餐厅
1715100175308 | 1 | main | 小白点了 番茄炒蛋 + 一碗米饭
1715100175325 | 1 | main | 小白开始打王者
1715100175326 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师炒菜
1715100175326 | 10 | ForkJoinPool.commonPool-worker-2 | 服务员打饭 //睡了4秒
1715100179338 | 9 | ForkJoinPool.commonPool-worker-9 | cf1线程结束
1715100179338 | 10 | ForkJoinPool.commonPool-worker-2 | cf2线程结束
1715100180331 | 1 | main | 主线程结束Process finished with exit code 0
- 测试3 等待异步调用的结果,根据结果再处理逻辑
public class Main {public static void main(String[] args) {SmallTools.printTimeAndThread("小白进入餐厅");SmallTools.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("厨师炒菜");SmallTools.sleepMillis(4000);SmallTools.printTimeAndThread("厨师打饭");SmallTools.sleepMillis(2000);return "番茄炒蛋 + 米饭";});SmallTools.printTimeAndThread("小白开始打王者");SmallTools.printTimeAndThread(String.format("%s做好了,小白开吃",cf1.join()));}
}----结果
1715098991592 | 1 | main | 小白进入餐厅
1715098991592 | 1 | main | 小白点了 番茄炒蛋 + 一碗米饭
1715098991608 | 1 | main | 小白开始打王者
1715098991610 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师炒菜 //睡了4秒
1715098995625 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师打饭 //睡了2s
1715098997637 | 1 | main | 番茄炒蛋 + 米饭做好了,小白开吃
- 测试4 链式调用,开启2个线程,第二个线程等待第一个线程结束后在异步调用
public class Main {public static void main(String[] args) {SmallTools.printTimeAndThread("小白进入餐厅");SmallTools.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("厨师炒菜");SmallTools.sleepMillis(4000);return "番茄炒蛋";}).thenCompose(dish -> CompletableFuture.supplyAsync(()->{SmallTools.printTimeAndThread("厨师打饭");SmallTools.sleepMillis(2000);return " + 米饭";}));SmallTools.printTimeAndThread("小白开始打王者");SmallTools.printTimeAndThread(String.format("%s 做好了,小白开吃",cf1.join()));}
}
------
1715100509306 | 1 | main | 小白进入餐厅
1715100509306 | 1 | main | 小白点了 番茄炒蛋 + 一碗米饭
1715100509323 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师炒菜
1715100509323 | 1 | main | 小白开始打王者 //等待4秒
1715100513328 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师打饭 //等待2秒
1715100515342 | 1 | main | + 米饭 做好了,小白开吃
- 测试5 同时开启2个异步调用,其实和测试2没什么区别,代码好看点
public class Main {public static void main(String[] args) {SmallTools.printTimeAndThread("小白进入餐厅");SmallTools.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("厨师炒菜");SmallTools.sleepMillis(4000);return "番茄炒蛋";}).thenCombine(CompletableFuture.supplyAsync(() -> {SmallTools.printTimeAndThread("服务员蒸饭");SmallTools.sleepMillis(4000);return "米饭";}),(dish,rice) -> {SmallTools.printTimeAndThread("服务员打饭");return dish + " + " +rice;});SmallTools.printTimeAndThread("小白开始打王者");SmallTools.printTimeAndThread(String.format("%s 做好了,小白开吃",cf1.join()));}
}
------
1715101146820 | 1 | main | 小白进入餐厅
1715101146820 | 1 | main | 小白点了 番茄炒蛋 + 一碗米饭
1715101146837 | 9 | ForkJoinPool.commonPool-worker-9 | 厨师炒菜
1715101146837 | 10 | ForkJoinPool.commonPool-worker-2 | 服务员蒸饭
1715101146838 | 1 | main | 小白开始打王者 //睡了4秒
1715101150852 | 9 | ForkJoinPool.commonPool-worker-9 | 服务员打饭
1715101150858 | 1 | main | 番茄炒蛋 + 米饭 做好了,小白开吃
相关文章:
CompletableFuture使用案例
优化代码时,除了Async注解,项目中如何使用多线程异步调用? 举个例子,去餐厅吃饭的时候。先点餐,厨师做菜,在厨师做菜的时候打游戏,然后根据厨师做的菜的口味去买矿泉水还是可乐。这样࿰…...
安卓使用so库
最近需要给小伙伴扫盲一下如何使用Android Studio 生成一个SO文件,网上找了很多都没有合适的样例,那只能自己来写一个了。 原先生成SO是一个很麻烦的事情,现在Android Studio帮忙做了很多的事情,基本只要管好自己的C代码即可。 …...
【介绍下LeetCode的使用方法】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
重学java 30.API 1.String字符串
于是,虚度的光阴换来了模糊 —— 24.5.8 一、String基础知识以及创建 1.String介绍 1.概述 String类代表字符串 2.特点 a.Java程序中的所有字符串字面值(如“abc”)都作为此类的实例(对象)实现 凡是带双引号的,都是String的对象 String s "abc&q…...
【区块链】共识算法简介
共识算法简介 区块链三要素: 去中心化共识算法智能合约 共识算法作为区块链三大核心技术之一,其重要性不言而喻。今天就来简单介绍共识算法的基本知识。 最简单的解释,共识算法就是要让所有节点达成共识,保证少数服从多数&#x…...
Qt---day2-信号与槽
1、思维导图 2、 拖拽式 源文件 #include "mywidget.h" #include "ui_mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::MyWidget) { ui->setupUi(this); //按钮2 this->btn2new QPushButton("按钮2",th…...
Python中设计注册登录代码
import hashlib import json import os import sys # user interface 用户是界面 UI """ 用户登录系统 1.注册 2.登陆 0.退出 """ # 读取users.bin def load(path): return json.load(open(path, "rt")) # 保存user.bin def save(dic…...
AI伦理和安全风险管理终极指南
人工智能(AI)正在迅速改变各个领域的软件开发和部署。驱动这一转变的两个关键群体为人工智能开发者和人工智能集成商。开发人员处于创建基础人工智能技术的最前沿,包括生成式人工智能(GenAI)模型、自然语言处理&#x…...
golang testing使用
testing包服务于自动化测试 基本测试 Table Drvien Test 基于表的测试通过表形式进行测试每种情况的输入和期望输出,从而测试程序的正确性 func TestFib(t *testing.T) {var fibTests []struct {in int // inputexpected int // expected result}{{1, 1}…...
在Excel中使用正则提取单元格内容
在办公自动化的浪潮中,Excel 作为数据处理的利器,一直在不断进化。最近,我注意到了不坑盒子Office插件一个非常实用的功能更新——bk_regex_string 公式。这个功能对于我们这些日常需要处理大量文本和数据的办公人员来说,无疑是一…...
SQL查询语句(二)逻辑运算关键字
上一篇文章中我们提到了条件查询除了一些简单的数学符号之外,还有一些用于条件判断的关键字,如逻辑判断 关键字AND,OR,NOT和范围查找关键字BETWEEN,IN等;下面我们来介绍一些这些关键字的用法以及他们所表达的含义。 目录 逻辑运算关键字 AND…...
矿山机械自动化中的激光雷达技术探索
在矿山机械自动化技术的快速发展中,激光雷达技术作为其关键组成部分,正发挥着越来越重要的作用。本文将深入探讨激光雷达在矿山机械自动化中的应用,以及其所面临的挑战与未来发展趋势。 一、激光雷达在矿山机械自动化中的应用 激光雷达技术…...
MOSFET场效应管栅极驱动电流的计算
MOSFET驱动 MOSFET场效应管是电压驱动器件,输入有电容,因此为可靠驱动MOSFET,栅极需要施加较大的驱动电流。 功率MOSFET开关模型 该模型显示了影响开关性能的最重要的寄生器件。 栅极所需驱动电流计算公式 一个很重要的参数是计算栅极驱…...
Python 爬虫:Spring Boot 反爬虫的成功案例
前言 在当今数字化时代,网络数据成为了信息获取和分析的重要来源之一。然而,随着网络数据的广泛应用,爬虫技术也逐渐成为了互联网行业的热门话题。爬虫技术的应用不仅可以帮助企业获取有价值的信息,还可以用于数据分析、市场研究…...
计算机毕业设计Python+Vue.js天气预测系统 中国气象质量采集与可视化 天气数据分析 天气可视化 天气大数据 天气爬虫 大数据毕业设计
摘要 随着科技技术的不断发展,人民物质生活质量不断提高,我们越来越关注身边的气象、空气等地理环境。对于普通居民我们会选择合适的气象进行出游,提高精神层面的生活质量;对于企业会关注气象变换状况,来定制相关的生产…...
【busybox记录】【shell指令】tr
目录 内容来源: 【GUN】【tr】指令介绍 【busybox】【tr】指令介绍 【linux】【tr】指令介绍 使用示例: 转换字符 - 默认 转换字符 - 不翻译指定字符数组 此指令目前接触少,用得少,把精力放到其他常用指令上 常用组合指令…...
Mac虚拟机软件哪个好用 mac虚拟机parallels desktop有什么用 Mac装虚拟机的利与弊 mac装虚拟机对电脑有损害吗
随着多系统使用需求的升温,虚拟机的使用也变得越来越普遍。虚拟机可以用于创建各种不同的系统,并按照要求设定所需的系统环境。另外,虚拟机在Mac电脑的跨系统使用以及测试软件系统兼容性等领域应用也越来越广泛。 一、Mac系统和虚拟机的区别 …...
Type-C转音频(USB2.0数据传输)+PD充电芯片乐得瑞LDR6500/LDR6023
LDR6500 USB-C DRP 接口 USB PD 通信芯片概述 Type-C转音频(USB2.0数据传输)PD充电芯片乐得瑞LDR6500LDR6500是乐得瑞科技针对USB Type-C标准中的Bridge设备而开发的USB-C DRP(Dual Role Port,双角色端口)接口USB PD(Power Deliv…...
【busybox记录】【shell指令】expand
目录 内容来源: 【GUN】【expand】指令介绍 【busybox】【expand】指令介绍 【linux】【expand】指令介绍 使用示例: 把制表符转化为空格 - 默认输出 把制表符转化为空格 - 修改制表符转空格的个数 把制表符转化为空格 - 修改制表符转空格的个数…...
软件测试—— 接口测试之通讯流程相关概念
通讯流程 1、协议 通讯规则 2、HTTP协议 协议的一种 3、接口规范文档 如何发请求的要求文档,获取什么响应内容的说明文档(相当于菜单)...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
