当前位置: 首页 > news >正文

springboot中使用async实现异步编程

目录

1.说明

2.实现原理

3.示例

4.总结


1.说明

@Async 是 Spring 框架提供的一个注解,用于标记方法为异步执行。被标记的方法将在调用时立即返回,而实际的方法执行将在单独的线程中进行。

@Async 注解有一个可选属性:指定要使用的特定线程池的 bean 名称

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {/*** 指定要使用的执行器(线程池)的限定符值*/String value() default "";
}

@Async 方法可以有以下返回类型:

  1. void:无返回值

  2. Future:返回 Future 对象,可用于获取异步执行结果

  3. CompletableFuture/ListenableFuture:更现代的异步结果处理方式

2.实现原理

基于 Spring AOP(面向切面编程)和任务执行器(TaskExecutor)框架。

3.示例

①启动类中开启异步支持

@EnableAsync  // 开启异步支持	
@SpringBootApplication	
public class Application {	public static void main(String[] args) {	SpringApplication.run(Application.class, args);	}	
}

EnableAsync有两个主要参数: mode及proxyTargetClass

@EnableAsync 通过 mode 属性来配置代理方式:

AdviceMode 枚举有两种选择:

  1. AdviceMode.PROXY (默认值) - 使用标准 Spring AOP 代理

    • 对接口使用 JDK 动态代理

    • 对类使用 CGLIB 代理

  2. AdviceMode.ASPECTJ - 使用 AspectJ 编织(weaving)

    • 需要额外的 AspectJ 依赖

    • 不需要接口也能代理

    • 可以代理更多方法类型(如 private 方法)

proxyTargetClass:指定使用CGLIB 代理还是JDK动态代理

proxyTargetClass = true 表示:

  • 强制使用 CGLIB 代理,即使目标类实现了接口

  • 代理目标类本身,而不是其实现的接口

  • 可以代理没有接口的类

默认行为(proxyTargetClass = false 或未指定)

  • 如果目标类实现了接口 → 使用 JDK 动态代理

  • 如果目标类没有实现接口 → 使用 CGLIB 代理

一般来说使用AdviceMode.PROXY及proxyTargetClass = true

②配置线程池

可以配置多个线程池

package com.example.demo1.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@Configuration
public class ThreadPoolConfig {@Bean("executorPool1")public ThreadPoolTaskExecutor executorPool1() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);// 核心线程数executor.setMaxPoolSize(10);// 最大线程数executor.setQueueCapacity(100);// 队列容量executor.setKeepAliveSeconds(60);// 空闲线程的存活时间executor.setThreadNamePrefix("demo1-pool-");// 线程名称前缀executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 拒绝策略,让调用者线程自己执行被拒绝的任务// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //默认的拒绝策略,会抛出RejectedExecutionException异常// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 拒绝策略,直接丢弃任务,不抛出异常// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());// 拒绝策略,丢弃队列中最老的任务,尝试再次提交当前任务executor.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成executor.setAwaitTerminationSeconds(60);           // 等待终止的最长时间(秒)return executor;}@Bean("executorPool2")public ThreadPoolTaskExecutor executorPool2() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);// 核心线程数executor.setMaxPoolSize(10);// 最大线程数executor.setQueueCapacity(100);// 队列容量executor.setKeepAliveSeconds(60);// 空闲线程的存活时间executor.setThreadNamePrefix("demo1-pool-");// 线程名称前缀executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 拒绝策略,让调用者线程自己执行被拒绝的任务// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //默认的拒绝策略,会抛出RejectedExecutionException异常// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 拒绝策略,直接丢弃任务,不抛出异常// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());// 拒绝策略,丢弃队列中最老的任务,尝试再次提交当前任务executor.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成executor.setAwaitTerminationSeconds(60);           // 等待终止的最长时间(秒)  不设置超时时间 ≠ 无限等待,而是会立即强制关闭return executor;// 配置组合	实际行为	是否推荐// wait=true + 不设置await	立即强制关闭	❌ 不推荐// wait=true + await=N	优雅等待N秒	✅ 推荐// wait=false	立即强制关闭	特殊场景使用}
}

 ③定义异步方法

package com.example.demo1.logic;import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;@Service
public class AsyncLogic {@Async("executorPool1")public CompletableFuture<String> process1(String item) {CompletableFuture<String> future = new CompletableFuture<>();try {System.out.println("线程名称:" + Thread.currentThread().getName());Thread.sleep(1000);future.complete("Processed: " + item);} catch (Exception e) {e.printStackTrace();future.completeExceptionally(e);}return future;}@Async("executorPool2")public Future<String> process2(String item) {try {System.out.println("线程名称:" + Thread.currentThread().getName());Thread.sleep(1000);return AsyncResult.forValue("Processed: " + item);} catch (Exception e) {e.printStackTrace();return AsyncResult.forExecutionException(e);}}@Async("executorPool1")public void process3(String item) {try {System.out.println("线程名称:" + Thread.currentThread().getName());Thread.sleep(1000);System.out.println("执行");} catch (Exception e) {e.printStackTrace();}}
}

④调用异步方法

package com.example.demo1;import com.example.demo1.logic.AsyncLogic;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;@SpringBootTest
public class AsyncTest {@Autowiredprivate AsyncLogic asyncLogic;@Testpublic void test114() {System.out.println("调用异步方法前");CompletableFuture<String> completableFuture = asyncLogic.process1("item");Future<String> item = asyncLogic.process2("item");asyncLogic.process3("item");System.out.println("执行其他操作,不阻塞主线程");try {System.out.println("获取异步任务结果,阻塞主线程");String result = completableFuture.get();System.out.println("异步任务结果1:" + result);String s = item.get();System.out.println("异步任务结果2:" + s);} catch (Exception e) {System.out.println("捕捉到异常");}System.out.println("调用异步方法后");}}

4.总结

1. 必须通过 Spring Bean 调用

❌ 错误:直接调用 this.asyncMethod()(同一类内调用不生效)。

✅ 正确:通过 @Autowired 注入自身或使用其他 Bean 调用。
2. 异常处理

默认静默吞异常,建议添加异常处理器:
异常时记录日志,并发送钉钉通知
3. 方法可见性

@Async 需作用于 public 方法,私有方法无效。

4.线程池的关闭

不需要手动关闭,Spring 容器会全自动管理声明为 @Bean 的线程池生命周期,包括应用正常关闭时的优雅终止


http://www.mrgr.cn/news/97588.html

相关文章:

  • 【蓝桥杯】动态规划背包问题
  • Go语言从零构建SQL数据库(5)-Pratt解析算法:SQL表达式解析的核心引擎
  • 算法与数据结构线性表之栈和队列
  • Docker与VNC的使用
  • PPTAgent:一款开源免费生成和评估幻灯片的项目
  • Linux信号——信号的保存(2)
  • Linux信号——信号的处理(3)
  • QT6(12)3.3.1 Qt元对象系统概述:QObject 类与 QMetaObject 类,类型转换 qobject_cast<T>()。3.3.3 属性系统:帮助文档,
  • 【题解-Acwing】798. 差分矩阵
  • 【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【代码篇】A题解题全流程(持续更新)
  • vue3 处理文字 根据文字单独添加class
  • linux第三次作业
  • JVM核心机制:类加载×字节码引擎×垃圾回收机制
  • 使用Docker安装及使用最新版本的Jenkins
  • el-table,新增、复制数据后,之前的勾选状态丢失
  • STM32江科大----IIC
  • 高安全等级车规芯片在星载控制终端上的应用
  • Nodejs回调函数
  • python应用之使用pdfplumber 解析pdf文件内容
  • 使用stm32cubeide stm32f407 lan8720a freertos lwip 实现udp client网络数据转串口数据过程详解