SpringBoot实现异步调用的几种方式

news2024/11/27 1:26:59

一、使用 CompletableFuture 实现异步任务

CompletableFuture 是 Java 8 新增的一个异步编程工具,它可以方便地实现异步任务。使用 CompletableFuture 需要满足以下条件:

  1. 异步任务的返回值类型必须是 CompletableFuture 类型;

  2. 在异步任务中使用 CompletableFuture.supplyAsync() 或 CompletableFuture.runAsync() 方法来创建异步任务;

  3. 在主线程中使用 CompletableFuture.get() 方法获取异步任务的返回结果。

我们创建一个服务类,里面包含了异步方法和普通方法。

import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步服务类
 */
@Service
public class AsyncService {


    /**
     * 普通任务操作1
     */
    public String task1() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        return "任务执行完成1";
    }

    /**
     * 普通任务操作2
     */
    public String task2() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return "任务执行完成2";
    }

    /**
     * 普通任务操作3
     */
    public String task3() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        return "任务执行完成3";
    }

    /**
     * 异步操作1
     */
    public CompletableFuture<String> asyncTask1() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "异步任务执行完成1";
        });
    }

    /**
     * 异步操作2
     */
    public CompletableFuture<String> asyncTask2() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "异步任务执行完成2";
        });
    }

    /**
     * 异步操作3
     */
    public CompletableFuture<String> asyncTask3() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "异步任务执行完成3";
        });
    }
}

我们先测试普通方法的情况,看看最后耗时

import cn.hutool.core.date.StopWatch;
import com.example.quartzdemo.service.AsyncService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步处理测试
 */
@SpringBootTest
public class AsyncTest {

    @Autowired
    private AsyncService asyncService;

    @Test
    void test1() throws InterruptedException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 异步操作
       /* CompletableFuture<String> completableFuture1 = asyncService.asyncTask1();
        CompletableFuture<String> completableFuture2 = asyncService.asyncTask2();
        CompletableFuture<String> completableFuture3 = asyncService.asyncTask3();

        System.out.println(completableFuture1.get());
        System.out.println(completableFuture2.get());
        System.out.println(completableFuture3.get());*/

        // 同步操作
        System.out.println(asyncService.task1());
        System.out.println(asyncService.task2());
        System.out.println(asyncService.task3());

        stopWatch.stop();
        System.out.println("耗时:" + stopWatch.getTotalTimeMillis());
    }
}

程序执行的结果:

任务执行完成1
任务执行完成2
任务执行完成3
耗时:8008

我们可以发现,普通同步方法是按顺序一个个操作的,各个方法不会同时处理。下面我们把这些操作换成异步的方法测试。

import cn.hutool.core.date.StopWatch;
import com.example.quartzdemo.service.AsyncService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步处理测试
 */
@SpringBootTest
public class AsyncTest {

    @Autowired
    private AsyncService asyncService;

    @Test
    void test1() throws InterruptedException, ExecutionException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 异步操作
        CompletableFuture<String> completableFuture1 = asyncService.asyncTask1();
        CompletableFuture<String> completableFuture2 = asyncService.asyncTask2();
        CompletableFuture<String> completableFuture3 = asyncService.asyncTask3();

        System.out.println(completableFuture1.get());
        System.out.println(completableFuture2.get());
        System.out.println(completableFuture3.get());

        // 同步操作
        /*System.out.println(asyncService.task1());
        System.out.println(asyncService.task2());
        System.out.println(asyncService.task3());*/

        stopWatch.stop();
        System.out.println("耗时:" + stopWatch.getTotalTimeMillis());
    }
}

程序执行结果:

异步任务执行完成1
异步任务执行完成2
异步任务执行完成3
耗时:3008

发现几个方法是异步同时进行的,没有先后的顺序,大大提高了程序执行效率。

二、基于注解 @Async实现异步任务

@Async 注解是 Spring 提供的一种轻量级异步方法实现方式,它可以标记在方法上,用来告诉 Spring 这个方法是一个异步方法,Spring 会将这个方法的执行放在异步线程中进行。使用 @Async 注解需要满足以下条件:

  1. 需要在 Spring Boot 主类上添加 @EnableAsync 注解启用异步功能;

  2. 需要在异步方法上添加 @Async 注解。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
// 主类上加上这个注解,开启异步功能
@EnableAsync
public class QuartzDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuartzDemoApplication.class, args);
    }

}

创建一个测试类

import cn.hutool.core.date.StopWatch;
import com.example.quartzdemo.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion:
 */
@RestController
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    /**
     * 测试异步
     */
    @RequestMapping("/async")
    public void testAsync() throws InterruptedException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        asyncService.asyncTask1();
        asyncService.asyncTask2();
        asyncService.asyncTask3();

        stopWatch.stop();
        System.out.println("耗时:" + stopWatch.getTotalTimeMillis());

    }
}

执行测试方法

 

耗时:5
异步任务执行完成2
异步任务执行完成3
异步任务执行完成1

三、使用 TaskExecutor 实现异步任务

TaskExecutor 是 Spring 提供的一个接口,它定义了一个方法 execute(),用来执行异步任务。使用 TaskExecutor 需要满足以下条件:

  1. 需要在 Spring 配置文件中配置一个 TaskExecutor 实例;

  2. 在异步方法中调用 TaskExecutor 实例的 execute() 方法来执行异步任务。

创建一个异步配置类

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步处理配置类
 */
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Bean(name = "asyncExecutor")
    public TaskExecutor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }

    @Override
    public Executor getAsyncExecutor() {
        return asyncExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

修改下服务类,我们使用自定义的异步配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步服务类
 */
@Service
public class AsyncService {

    @Autowired
    @Qualifier("asyncExecutor")
    private TaskExecutor taskExecutor;


    /**
     * 同步任务操作1
     */
    public String task1() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        return "任务执行完成1";
    }

    /**
     * 同步任务操作2
     */
    public String task2() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return "任务执行完成2";
    }

    /**
     * 同步任务操作3
     */
    public String task3() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        return "任务执行完成3";
    }


    /**
     * 异步操作1
     */
    @Async
    public void asyncTask1() {
        taskExecutor.execute(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println("异步任务执行完成1");
    }

    /**
     * 异步操作2
     */
    @Async
    public void asyncTask2() throws InterruptedException {
        taskExecutor.execute(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println("异步任务执行完成2");
    }

    /**
     * 异步操作3
     */
    @Async
    public void asyncTask3() throws InterruptedException {
        taskExecutor.execute(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println("异步任务执行完成3");
    }
    
}

测试类进行测试

/**
 * @author qinxun
 * @date 2023-06-07
 * @Descripion: 异步处理测试
 */
@SpringBootTest
public class AsyncTest {
    
    @Autowired
    @Qualifier("asyncExecutor")
    private TaskExecutor taskExecutor;


    @Test
    void test1() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 异步操作
       /* asyncService.asyncTask1();
        asyncService.asyncTask2();
        asyncService.asyncTask3();*/
        taskExecutor.execute(() -> System.out.println("异步任务"));

        // 同步操作
        /*System.out.println(asyncService.task1());
        System.out.println(asyncService.task2());
        System.out.println(asyncService.task3());*/

        stopWatch.stop();
        System.out.println("耗时:" + stopWatch.getTotalTimeMillis());
    }
}
耗时:6
异步任务执行完成3
异步任务执行完成1
异步任务执行完成2

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

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

相关文章

基于vasp计算材料红外与Raman光谱信息

使用方法一&#xff1a;获取材料raman活性信息 代码链接&#xff1a;VASP/Sibulk-VASP at master raman-sc/VASP GitHub 前置计算材料的振动频率和介电常数等&#xff0c;参考INCAR如下&#xff1a; SYSTEM Si_bulk ISTART 0 # From-scratch; job : 0-new 1-cont 2-same…

4-2 贪心算法的基本要素

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 1.什么是贪心选择性质 贪心选择性质是一种在算法设计中经常使用的策略。它基于这样的思想&#xff1a;在每一步选择中&#xff0c;都选择当前看起来最优…

多篇论文入选ICASSP 2023,火山语音有效解决多类实践问题

近日由IEEE主办、被誉为世界范围内最大规模、也是最全面的信号处理及其应用方面的顶级学术会议ICASSP2023于希腊召开&#xff0c;该会议具有权威、广泛的学界以及工业界影响力&#xff0c;备受AI领域多方关注。会上火山语音多篇论文被接收并发表&#xff0c;内容涵盖众多前沿领…

superset db upgrade报错记录

superset db upgrade报错记录 报错1报错2报错3报错4报错5报错6成功了 报错1 (superset) [hyjhadoop102 ~]$ superset db upgradefrom markupsafe import soft_unicode ImportError: cannot import name soft_unicode from markupsafe (/opt/module/miniconda3/envs/superset/l…

git基本操作(笔记)

安装 查看是否安装成功 git --version配置用户名和邮箱 参数global表示全局配置&#xff0c;对所有仓库生效&#xff0c;system表示系统配置&#xff0c;对所有用户生效&#xff0c;省略是&#xff08;local&#xff09;表示本地配置&#xff0c;只对本地仓库有效。 git config…

奇安信 渗透测试(攻防类)一面复盘

奇安信 渗透测试&#xff08;攻防类&#xff09;一面复盘 1.你是哪里人2.你是做安全研发的&#xff0c;在qax这边除了这个红队的岗位还投递其他了吗3.看你研发做的比较多&#xff0c;为什么投递这个岗位4.给了一个具体的场景&#xff0c;问你做渗透测试的思路5.后渗透有了解吗&…

form-inserter 让你的表单插入更轻松

挖SRC的时候经常需要向 input 框或者textarea 框中插入一些payload&#xff0c;但是遇到某个网页需要插入的输入框很多或者payload 很复杂的时候&#xff0c;就需要多次复制粘贴&#xff0c;过程比较繁琐。 例如如下两种情况: 情况1&#xff1a;输入框很多 情况2&#xff1a;…

C语言趣味小游戏---利用二维数组实现三子棋游戏

学习了C语言中的二维数组&#xff0c;本照着学以致用的原则&#xff0c;现在利用对二维数组的操作来实现一个简单版的三子棋游戏。 三子棋其实我们都玩过&#xff0c;在我们这边又叫"一条龙"。就是一个九空格&#xff0c;下棋的双方依次在九个空格里面下棋&#xff0…

Jetson Nano之ROS入门 - - SLAM之Gmapping建图与路径规划

文章目录 前言一、Gmapping建图算法1、Gmapping算法流程原理2、Gmapping建图实操 二、AMCL蒙特卡洛定位1、自适应蒙特卡洛定位算法原理2、AMCL定位实操 三、move_base路径规划1、路径规划算法简介2、代价地图简介2、move_base路径规划实操 总结 前言 SLAM&#xff08;Simultane…

Water valve concept流水法判断D-separation

Water valve concept流水法判断D-separation 文章目录 Water valve concept流水法判断D-separationD-separation流水法判断例子 D-separation 概率图模型中的D-separation是一种刻画随机变量之间条件独立性的方法。具体来说&#xff0c;给定一个概率图模型&#xff0c;如果其中…

Yarn【关于配置yarn-site.xml的注意事项】

注意事项 配置文件的<description>表签内容可以删&#xff0c;不影响配置文件的读取。最重要的<name><value>标签中间的内容一定要好好检查&#xff0c;尤其是在复制别人的配置信息的时候格外要注意&#xff1a;value中有没有空格、有没有因为你打开工具的不…

【IT经验实战】教你如何真正有效地学习一门IT技术

前言 在写博客之前&#xff0c;我在CSDN中搜寻了一下 “如何系统学习一门it技术” &#xff0c;琳琅满目&#xff0c;有些借鉴了ChatGPT生成的内容&#xff08;几乎一模一样&#xff09;、有些写得比较笼统没有针对性、有的偏向理论难以实操。 下文内容着实强调求学经历和过程…

SpringCloud组件介绍

一&#xff1a;什么是微服务&#xff08;Microservice&#xff09; 微服务英文名称Microservice&#xff0c;Microservice架构模式就是将整个Web应用组织为一系列小的Web服务。这些小的Web服务可以独立地编译及部署&#xff0c;并通过各自暴露的API接口相互通讯。它们彼此相互协…

小作文--流程图(练习1)

【【雅思写作】带你打破小作文‘流程图’的传说】 https://www.bilibili.com/video/BV1QP411Q7Gh/?share_sourcecopy_web&vd_source78768d4ae65c35ff26534bbaa8afc267 雅思小作文-流程图, 看这一篇就够了! - 冯凯文的文章 - 知乎 https://zhuanlan.zhihu.com/p/35868880 …

跳出零和博弈,AIGC是元宇宙的“催命符”还是“续命丹”?

文 | 智能相对论 作者 | 青月 从科幻小说《雪崩》里走出来的元宇宙&#xff0c;如今正在上演“地价雪崩”。 CoinGecko的一项调查显示&#xff0c;Otherdeed for Otherside、The Sandbox、Decentraland、Somnium Space和Voxels Metaverse 这五款知名元宇宙土地价格近期均出现…

Linux发送接收邮件

目录 一、实验 1.linux用户发送给linux中的其它用户 2.linux用户发送给外网用户 一、实验 1.linux用户发送给linux中的其它用户 &#xff08;1&#xff09;使用命令 yum install -y sendmail 安装sendmail软件 &#xff08;2&#xff09;使用yum install -y mailx 安装 mail…

获奖名单公布|Builder House首尔站及首次线下黑客松圆满收官!

由Sui基金会举办的Builder House首尔站于6月4日圆满收官&#xff0c;为期两天半的活动吸引了来自全球各地的区块链专业人士和Sui生态项目爱好者前来参加。 出席本次活动的Sui基金会成员有活动负责人Anthony、开发者关系工程师Will & Henry & Shayan、增长负责人Koh &a…

高校毕业就业信息管理系统

基于SpringSpringMVCMybatis实现的高校毕业就业信息管理系统 主要模块&#xff1a; 1&#xff09;学生模块&#xff1a; 已投简历、未投简历、录入简历、浏览招聘中岗位、 浏览已投岗位、未提交面试问卷、已提交面试问卷、 收到的就业协议、签订成功的就业协议、个人基本信…

mac docker桌面版k8s启动成功却无法访问

1. 问题复现 在mac使用docker桌面版搭建k8s 成功 但是 kubectl 控制k8s集群命令却无法使用 报错信息如下 使用登录的用户访问 ~ kubectl version W0607 14:32:39.410809 54201 loader.go:221] Config not found: /etc/kubernetes/a…

【Docker】2.Docker安装

文章目录 DockerDocker Official WebsiteDocker InstallDocker Change ImageDocker Change Dir Docker Docker本质其实时LXC之类的增强版&#xff0c;它本身不是容器&#xff0c;而是容器的易用工具。Docker时让容器技术普及开来的最成功的实现。它的主要目标是"Build, S…