Springboot利用CompletableFuture异步执行线程(有回调和无回调)

news2024/11/26 2:52:31

目录

背景

实现

一、异步线程配置类

 二、自定义异步异常统一处理类

三、实现调用异步(无回调-runAsync())

四、实现调用异步(有回调-supplyAsync())  

五、异步执行错误异常示例

背景

项目中总会有需要异步执行来避免浪费时间资源的情况,这就需要异步操作。异步又分两种:

1、无回调:有一些执行过程对用户而言不需要反馈回调,只需要自己执行即可,且执行过程时间较长(某些第三方接口,如发送短信验证码、查取ip属地等等),如果同步执行,势必会影响到用户体验,这时候就可以使用CompletableFuture.runAsync()方法了。

2、有回调:在执行异步操作结束后,需要获得异步方法返回的值,然后再回调给用户展示,这时候就需要用到CompletableFuture.supplyAsync()方法了。

实现

一、异步线程配置类

/**
 * 异步线程配置类
 */
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(8);
        // 设置最大线程数
        executor.setMaxPoolSize(20);
        // 设置队列大小
        executor.setQueueCapacity(Integer.MAX_VALUE);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置线程名前缀+分组名称
        executor.setThreadNamePrefix("AsyncOperationThread-");
        executor.setThreadGroupName("AsyncOperationGroup");
        // 所有任务结束后关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 初始化
        executor.initialize();
        return executor;
    }

    /**
     * 自定义异步异常
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncException();
    }
}

 二、自定义异步异常统一处理类

/**
 * 异步请求异常错误
 */
public class AsyncException  implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
        System.out.println("--------------------异步请求异常捕获---------------------------------");
        System.out.println("Exception message - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
        System.out.println("---------------------异步请求异常捕获---------------------------------");
    }
}

三、实现调用异步(无回调-runAsync()

在需要异步的方法前加上@Async再调用即可如下,在service层中新建一个方法,模拟第三方接口请求延时3秒(异步方法和调用方法一定要写在不同的类中 ,如果写在一个类中,是没有效果的!)

@Service
public class LoginLogServiceImpl extends ServiceImpl<LoginLogMapper, LoginLog> implements ILoginLogService {

    // 无回调
    @Async
    public CompletableFuture<Void> test() {
        return CompletableFuture.runAsync(() -> {

            // 模拟第三方请求加载时间
            Thread.sleep(3000);

            System.out.println("保存成功登录日志");
        });
    }
}

 然后在controller层中调用该方法,

    @PostMapping("/login")
    public Result login() throws InterruptedException {

        System.out.println("登录验证成功");

        // 异步操作
        iLoginLogService.test();

        System.out.println("登录接口请求返回用户成功");

        // 正常返回结果
        return Result.success(200, "登录成功");
    }

执行完成后,我们打开控制台,可以看到, 异步请求在接口执行正常,在接口返回结果后执行完成。

四、实现调用异步(有回调-supplyAsync())  

这里我们多采用3个异步线程来模拟实际效果,且延迟时间为1 6 3,看下他们的异步执行输出顺序是否和我们模拟的执行时间相同,如下:

@Service
public class LoginLogServiceImpl extends ServiceImpl<LoginLogMapper, LoginLog> implements ILoginLogService {

    // 有返回值的异步方法CompletableFuture.supplyAsync()
    public CompletableFuture<String> test1() {
        return CompletableFuture.supplyAsync(() -> {
            ThreadUtil.sleep(1000);
            System.out.println("test1异步请求结果有返回");
            return "aaa";
        });
    }

    public CompletableFuture<String> test2() {
        return CompletableFuture.supplyAsync(() -> {
            ThreadUtil.sleep(6000);
            System.out.println("test2异步请求结果有返回");
            return "bbb";
        });
    }

    public CompletableFuture<String> test3() {
        return CompletableFuture.supplyAsync(() -> {
            ThreadUtil.sleep(3000);
            System.out.println("test3异步请求结果有返回");
            return "ccc";
        });
    }
}

 在controller层中利用CompletableFuture的get()方法获取数据,但是要加上try/catch捕获异常

@PostMapping("/login")
    public Result login() {

        System.out.println("登录验证成功");

        // 异步保存登录成功日志
        CompletableFuture<String> future1 = iLoginLogService.test1();
        CompletableFuture<String> future2 = iLoginLogService.test2();
        CompletableFuture<String> future3 = iLoginLogService.test3();

        System.out.println("模拟正常执行的方法");

        String result1 = "111";
        String result2 = "222";
        String result3 = "333";
        String result = "";
        
        // 需要用try/catch来获取异步返回值
        try {
            
            // get()方法获取返回值,并设置10秒超时就放弃,直接报错
            result1 = future1.get(10, TimeUnit.SECONDS);
            result2 = future2.get(10, TimeUnit.SECONDS);
            result3 = future3.get(10, TimeUnit.SECONDS);

            System.out.println("返回结果为:" + result1);
            System.out.println("返回结果为:" + result2);
            System.out.println("返回结果为:" + result3);

            result = result1 + result2 + result3;

            // 正常返回结果
            return Result.success(200, "登录成功", result);
        } catch (Exception e) {
            System.out.println(e);
            return Result.success(501, "登录失败,异常错误");
        }
    }

 结果可以看到如下图所示,异步线程同时执行,但最后返回结果是等所有线程执行完成后,再返回,这就是有回调的异步操作:

五、异步执行错误异常示例


    // 无回调
    @Async
    public CompletableFuture<Void> test() {
        return CompletableFuture.runAsync(() -> {

            // 模拟第三方请求加载时间
            Thread.sleep(1000);
        
            // 异常错误模拟
            Integer test = 1/0;

            System.out.println("异步请求开始执行完成");
        });
    }

 结果就是完全不影响接口执行,且打印出报错信息,如下:

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

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

相关文章

Windows中将tomcat以服务的形式安装,然后在服务进行启动管理

Windows中将tomcat以服务的形式安装,然后在服务进行启动管理 第一步&#xff1a; 在已经安装好的tomcat的bin目录下&#xff1a; 输入cmd&#xff0c;进入命令窗口 安装服务&#xff1a; 输入如下命令&#xff0c;最后是你的服务名&#xff0c;避免中文和特殊字符 service.…

Redis数据类型及命令

目录 &#xff08;一&#xff09;通用命令&#xff08;二&#xff09;String类型&#xff08;三&#xff09;Hash类型&#xff08;四&#xff09;List类型&#xff08;五&#xff09;Set类型&#xff08;六&#xff09;SortedSet类型 在redis命令行查询redis通用命令&#xff1…

如何使用摩尔信使MThings连接网络设备

帽子&#xff1a; 摩尔信使MThings支持Modbus-TCP、Modbus-RTU Over TCP、Modbus-TCP Over UDP、Modbus-RTU Over UDP。 TCP链接中&#xff0c;摩尔信使MThings支持灵活的连接方式&#xff0c;主机可作为客户端也可以作为服务端&#xff0c;同时支持模拟从机以客户端方式向远…

1600*C. Add One(数位DP找规律)

Problem - 1513C - Codeforces 解析&#xff1a; 考虑DP&#xff0c;DP[ i ] 为从 0 开始执行 i 次操作&#xff0c;此时数字的位数。 我们发现当一个9再操作一次就会变成1和0&#xff0c;并且相邻的大部分长度都不会变化&#xff0c;0会影响10次操作之后的位数&#xff0c;1会…

开源自动化测试框架优缺点对比

1. Robot Framework Robot Framework&#xff08;RF&#xff09;是用于验收测试和验收测试驱动开发&#xff08;ATDD&#xff09;的自动化测试框架。 基于 Python 编写&#xff0c;但也可以在 Jython&#xff08;Java&#xff09;和 IronPython&#xff08;.NET&#xff09; 上…

网页版微信CRM系统,让微信管理更方便!

微信&#xff0c;作为现在热门的社交软件之一&#xff0c;已经成为商家和消费者交流的主要渠道。但对于客服这类人群来说&#xff0c;一个得管理多个微信号&#xff0c;耗费了他们大量时间精力。 因此&#xff0c;微信CRM 系统应运而生。它可以将多个微信聚合在一个界面中&…

PPO算法逐行代码详解

前言&#xff1a;本文会从理论部分、代码部分、实践部分三方面进行PPO算法的介绍。其中理论部分会介绍PPO算法的推导流程&#xff0c;代码部分会给出PPO算法的各部分的代码以及简略介绍&#xff0c;实践部分则会通过debug代码调试的方式从头到尾的带大家看清楚应用PPO算法在car…

三、静态路由实验

拓扑图&#xff1a; 两个路由器分了三个网段出来&#xff0c;首先对两台PC机进行配置 进入R1路由器对两边链路进行ip配置 对AR2进行相同的配置&#xff0c;然后我们查看R1的路由表&#xff0c;里面有一些直连的信息。 三个网段的设备现在可以互通&#xff0c;我们要实现跨网段…

[数据结构]——单链表超详细总结

带你走进链表的世界 目录&#xff1a;一、线性表的概念二、顺序表三、链表3.1 链表的概念3.2 链表的分类3.3 无头单向非循环链表的实现3.4 带头双向循环链表的实现 四、顺序表和链表的区别和联系 目录&#xff1a; 链表是个优秀的结构&#xff0c;没有容量概念&#xff0c;可以…

Python接口测试 requests.post方法中data与json参数区别

引言 requests.post主要参数是data与json&#xff0c;这两者使用是有区别的&#xff0c;下面我详情的介绍一下使用方法。 Requests参数 1. 先可以看一下requests的源码&#xff1a; 1 2 3 4 5 6 7 8 9 10 11 12 13 def post(url, dataNone, jsonNone, **kwargs): r&quo…

STM32CUBEMX_DMA串口空闲中断接收+接收发送缓冲区

STM32CUBEMX_DMA串口空闲中断接收接收发送缓冲区 前言&#xff1a; 我了解的串口接收指令的方式有&#xff1a;在这里插入图片描述 1、接收数据中断特定帧尾 2、接收数据中断空闲中断 3、DMA接收空闲中断 我最推荐第三种&#xff0c;尤其是数据量比较大且频繁的时候 串口配置 …

Vmware Linux虚拟机安装教程(Centos版)

文章目录 1.Vmware-workstation安装软件2.双击下载的安装包开始安装3.打开VMware-workstation&#xff0c;输入密钥4.Centos7.6安装软件5.新建虚拟机6.为虚拟机配置映像文件7.开启虚拟机&#xff0c;配置环境7.1 Install Centos 77.2 选择简体中文字体7.3 软件选择7.4 安装位置…

LeetCode【20】 有效的括号

题型&#xff1a;栈 题目&#xff1a; 代码&#xff1a; public boolean isValidReview(String s) {//&#xff08;1&#xff09;从s的i0位置一次开始压栈&#xff0c;遇到左括号压栈&#xff0c;不管是大中小三种&#xff0c;左括号&#xff0c;压//&#xff08;2&#xf…

基于 EventBridge 轻松搭建消息集成应用

作者&#xff1a;昶风 前言 本篇文章主要介绍基于阿里云 EventBridge 的消息集成能力&#xff0c;结合目前消息产品的需求热点&#xff0c;从能力范围到场景实战&#xff0c;对 EventBridge 的消息集成解决方案进行了概要的介绍。 从消息现状谈起 消息队列作为应用解耦&…

Redis 基础—Redis Desktop Manager(Redis可视化工具)安装及使用教程

Redis Desktop Manager 是一个可视化的 Redis 数据库管理工具&#xff0c;可以方便地查看和操作 Redis 数据库。使用 Redis Desktop Manager 可以大大提高 Redis 数据库的管理效率。 RDM的安装和配置 首先&#xff0c;您需要下载和安装Redis Desktop Manager。 安装完成后&am…

高校教务系统密码加密逻辑及JS逆向——皖南医学院

高校教务系统密码加密逻辑及JS逆向 本文将介绍高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文&#xff0c;你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习&#xff0c;勿用于非法用途。 一、密码加…

提升企业服务行业管理效率的关键策略与方法」

To B 服务&#xff0c;也即企业服务近年来大家关注的重点&#xff0c;企业服务是指为企业客户提供运营管理相关的工具与系统解决方案等服务&#xff0c;通过专业化的服务可以实现降本增效&#xff0c;提高企业的经营效率。 近年来&#xff0c;人口红利的消失促使企业服务需求快…

DC电源模块低温是否影响转换效率

BOSHIDA DC电源模块低温是否影响转换效率 DC电源模块是一种常用的电源转换装置&#xff0c;其主要作用是将输入的电源信号变换成需要的输出电源信号。在实际应用中&#xff0c;DC电源模块的性能会受到多种因素的影响&#xff0c;其中低温也是一个重要的影响因素。本文将从转换…

kettle应用-从数据库抽取数据到excel

本文介绍使用kettle从postgresql数据库中抽取数据到excel中。 首先&#xff0c;启动kettle 如果kettle部署在windows系统&#xff0c;双击运行spoon.bat或者在命令行运行spoon.bat 如果kettle部署在linux系统&#xff0c;需要执行如下命令启动 chmod x spoon.sh nohup ./sp…

c++设计模式之单例设计模式

&#x1f482; 个人主页:[pp不会算法v](https://blog.csdn.net/weixin_73548574?spm1011.2415.3001.5343) &#x1f91f; 版权: 本文由【pp不会算法^v^】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦…