当前位置: 首页 > 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 {

    @Autowired
    private AsyncLogic asyncLogic;


    @Test
    public 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 的线程池生命周期,包括应用正常关闭时的优雅终止

相关文章:

  • Docker Compose 部署Nginx反向代理 tomcat
  • 每日算法-250407
  • 数字经济产业标杆:树莓集团如何塑造产业服务价值体系
  • 没有独立显卡如何安装torch
  • 极简设计的力量:用 `apiStore` 提升项目效率与稳定性
  • oracle查询是否锁表了
  • Objective-C语言的编程范式
  • 昇腾910b多机部署deepseek-r1-w8a8量化全攻略
  • Hive 常见面试 300 问
  • leetcode 368. 最大整除子集 中等
  • Scala(六)
  • Matlab绘图—‘‘错误使用 plot输入参数的数目不足‘‘
  • 工程项目中通讯协议常见问题
  • 零代码构建AI知识库:基于亮数据网页抓取API的维基百科数据自动化采集实战
  • 昂贵的DOM操作:一次DOM导致的性能问题排查记录
  • 自动化测试是什么?Selenium实战!
  • 【分享开发笔记,赚取电动螺丝刀】使用STM32F103的hal库,采用PWM+DMA发送方式驱动WS2812的RGB彩灯
  • k8s介绍
  • Ansible 入门教程:从零开始掌握自动化运维
  • LiteFlow[规则引擎]简单介绍和它的设计模式
  • 张巍任中共河南省委副书记
  • 师爷、文士、畸人:会稽范啸风及其著述
  • 商务部:长和集团出售港口交易各方不得规避审查
  • 问责!美国海军对“杜鲁门”号航母一系列事故展开调查
  • 2025年中国网络文明大会将于6月10日在安徽合肥举办
  • 四部门:强化汛期农业防灾减灾,奋力夺取粮食和农业丰收