SpringBoot 异步任务处理

简介: SpringBoot 异步任务处理

SpringBoot配置异步任务

有些业务是不需要你同步去操作的, 例如: 适用于处理log、发送邮件、短信……等

我们不能因为短信没发出去而没有执行接下来的业务逻辑, 这个时候我们就应该去把这些耗时的任务弄成异步的

  • 首先要在启动类里面增加如下注解
@EnableAsync
  • 定义异步任务类并使用@Component标记组件被容器扫描,异步方法加上@Async

如果整个类的操作都是异步的话 @Async 可以给类加上, 要把异步任务封装到类里面,不能直接写到Controller

  • TestTaskController.java
package com.cj.tool.comtool.controller;
import com.cj.tool.comtool.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestTaskController {
    @Autowired
    private AsyncTask asyncTask;
    // 直接调起异步任务。正常执行肯定是堵塞的
    @GetMapping("/api/v1/test_task")
    public long testTask() throws InterruptedException {
        long begin = System.currentTimeMillis();
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
        long end = System.currentTimeMillis();
        System.out.println("Controller 执行时间" + (end - begin));
        return end - begin;
    }
}
  • AsyncTask.java
package com.cj.tool.comtool.task;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Async
public class AsyncTask {
    public void task1() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("task1耗时:"+ (end - begin));
    }
    public void task2() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        System.out.println("task2耗时:"+ (end - begin));
    }
    public void task3() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(3000);
        long end = System.currentTimeMillis();
        System.out.println("task3耗时:"+ (end - begin));
    }
}

可以看到在AsyncTask里面都是有sleep的, 但是我们使用了异步

Controller执行时间 是先输出的, 我们的任务去开另外的线程执行, 这样大大增加了我们的程序效率, 在项目里面合适使用异步任务, 可以大大提高我们的QPS

获取异步返回数据

上面例子虽然解决了堵塞的问题, 但是有的时候我们希望获取异步任务的返回结果, 再进行后续工作。放心 这个也有方案

添加异步返回任务

  • AsyncTask.java
public Future<String> task4() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(4000);
        long end = System.currentTimeMillis();
        System.out.println("task4耗时:"+ (end - begin));
        return new AsyncResult<>("Task4的数据");
    }
    public Future<Integer> task5() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(5000);
        long end = System.currentTimeMillis();
        System.out.println("task5耗时:"+ (end - begin));
        return new AsyncResult<>(123);
    }
    public Future<String> task6() throws InterruptedException {
        long begin = System.currentTimeMillis();
        Thread.sleep(6000);
        long end = System.currentTimeMillis();
        System.out.println("task6耗时:"+ (end - begin));
        return new AsyncResult<>("Task6的数据");
    }
  • TestTaskController.java
@GetMapping("/api/v1/test_task")
    public long testTask() throws InterruptedException, ExecutionException {
        long begin = System.currentTimeMillis();
//        asyncTask.task1();
//        asyncTask.task2();
//        asyncTask.task3();
        Future<String> task4Result = asyncTask.task4();
        Future<Integer> task5Result = asyncTask.task5();
        Future<String> task6Result = asyncTask.task6();
        // 等每个任务执行完了就跳出
        for (;;) {
            if (task4Result.isDone() && task5Result.isDone() && task6Result.isDone()) {
                break;
            }
        }
        // 获取返回结果
        String task4res = task4Result.get();
        int task5res = task5Result.get();
        System.out.println(task4res);
        System.out.println(task5res);
        long end = System.currentTimeMillis();
        System.out.println("Controller 执行时间" + (end - begin));
        return end - begin;
    }

说一下流程

1)增加Future<String> 返回结果需呀 new AsyncResult<String>("task执行完成");


2)如果需要拿到结果 需要判断全部的 task.isDone(), 然后再task.get() 获取返回数据

  • 效果

可以看到 还是异步的, 最长耗时6000, 这样就可以应对不同的业务了, 如果是同步的话肯定需要 15000

目录
相关文章
|
3月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
177 1
|
2月前
|
存储 安全 Java
SpringBoot异步任务获取HttpServletRequest
通过上述方法,我们可以在Spring Boot应用中的异步任务获取 `HttpServletRequest`,从而实现更为灵活和高效的异步处理逻辑。
258 64
消息中间件 缓存 监控
115 0
|
3月前
|
监控 Java API
Spring Boot中的异步革命:构建高性能的现代Web应用
【8月更文挑战第29天】Spring Boot 是一个简化 Spring 应用开发与部署的框架。异步任务处理通过后台线程执行耗时操作,提升用户体验和系统并发能力。要在 Spring Boot 中启用异步任务,需在配置类上添加 `@EnableAsync` 注解,并定义一个自定义的 `ThreadPoolTaskExecutor` 或使用默认线程池。通过 `@Async` 注解的方法将在异步线程中执行。异步任务适用于发送电子邮件、数据处理、外部 API 调用和定时任务等场景。最佳实践中应注意正确配置线程池、处理返回值和异常、以及监控任务状态,确保系统的稳定性和健壮性。
41 0
|
3月前
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
36 0
|
4月前
|
Java Spring 容器
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
203 3
|
4月前
|
存储 Java Spring
SpringBoot异步任务获取HttpServletRequest
这样的操作对于保持异步操作中的请求上下文十分有用,特别是当你需要在日志记录、权限检查或者其他需要请求信息的场景中。确保上下文的正确传递和管理对于构建可靠的,异步处理能力很强的Spring Boot应用至关重要。
284 3
|
3月前
|
Java 数据安全/隐私保护
SpringBoot 自定义初始化任务 Runner
SpringBoot 自定义初始化任务 Runner
16 0
|
4月前
|
SQL Java 调度
实时计算 Flink版产品使用问题之使用Spring Boot启动Flink处理任务时,使用Spring Boot的@Scheduled注解进行定时任务调度,出现内存占用过高,该怎么办
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
4月前
|
前端开发 Java 应用服务中间件
SpringBoot异步接口怎么实现?
### 前言 Servlet 3.0以前,每个HTTP请求由单一线程全程处理;3.0版本引入异步处理,允许提前释放容器线程,提升系统吞吐量。