千家信息网

springboot @Async 注解如何实现方法异步

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章给大家介绍springboot @Async 注解如何实现方法异步,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。@Async注解如何实现方法异步处理大批量数据的时候,效率
千家信息网最后更新 2026年11月03日springboot @Async 注解如何实现方法异步

这篇文章给大家介绍springboot @Async 注解如何实现方法异步,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

@Async注解如何实现方法异步

处理大批量数据的时候,效率很慢。所以考虑一下使用多线程。

刚开始自己手写的一套,用了线程池启动固定的线程数进行跑批。但是后来老大考虑到自己手写的风险不好控制,所以使用spring的方法。

这里没有详细介绍,只有简单的demo,只会用,不懂原理:

一、springboot的App类需要的注解

package com.xxx.xxx.xxx;import java.util.concurrent.ThreadPoolExecutor;import org.springframework.boot.web.support.SpringBootServletInitializer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.TaskExecutor;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;/** * 类功能说明:服务生产者启动类 * 

* *

* * @version * @author * @since 1.8 */@Configuration@EnableAsyncpublic class Application extends SpringBootServletInitializer { @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数 executor.setCorePoolSize(5); // 设置最大线程数 executor.setMaxPoolSize(60); // 设置队列容量 executor.setQueueCapacity(20); // 设置线程活跃时间(秒) executor.setKeepAliveSeconds(60); // 设置默认线程名称 executor.setThreadNamePrefix("what-"); // 设置拒绝策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }

springboot的App类,很简单,就能使用很多东西。

二、service层的注解

package com.xxx.xxx.service.impl; import java.util.concurrent.Future; import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.AsyncResult;import org.springframework.stereotype.Service; import com.xxx.xxx.service.XXXAsyncService ; @Servicepublic class XXXAsyncServiceImpl implements XXXAsyncService {     @Async    public Future rtn1() throws Exception {        //do something        //有返回值的时候,可以返回string,long之类的。        return new AsyncResult<>(1);    }     @Async    public void rtn2() throws Exception {        //do something        //这个可以没有返回值.    }}

三、调用层

package com.xxx.xxx.controller; import java.util.concurrent.Future; import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController; import com.xxx.xxx.service.XXXAsyncService; @RestController@RequestMapping(value="/xxx") public class XXXAsyncController {  @Autowired private XXXAsyncService xxxAsyncService;  /**  * 这里调用异步方法  */    @RequestMapping(value = "/xxx") public void dodo() throws Exception {       int threads = 10;//十个线程        List> list = new ArrayList<>();        for(int i = 0;i < threads; i++){         //这里循环调用异步方法。      //如果存在大量数据,可以在这里把数据切片,然后循环调用,分批处理数据。效率杠杠的。   list .add(xxxAsyncService.rtn1());        }        long count = 0;        for(Future l : tsfCountList) {         //异步调用需要返回值的时候,这里可以把返回值都放入到list集合中,然后可以统一处理。 这里的get()是阻塞的,因为需要所以异步方法返回,在继续执行。         count += l.get();        }        System.out.println("调用次数:" + count); }}

这些代码全是手写,记录下来,以后用的时候,省的忘了,查起来麻烦。。

异步注解@Async的使用以及注意事项

第一步开启异步

@Configuration@EnableAsyncpublic class SpringAsyncConfig { ... }

默认情况下,@EnableAsync检测Spring的@Async注释和EJB 3.1 javax. EJB .异步;此选项还可用于检测其他用户定义的注释类型。(也可以在SpringBoot的启动类上直接加@EnableAsync注解)

在 Spring 中,用 @Async 注解指定的方法,该方法被调用时会以异步的方式执行。而如果没有在 @Async 注解中指定线程池,就会使用默认的线程池。默认的线程池为 SimpleAsyncTaskExecutor 。

该线程池不会复用线程,每有一个新任务被提交,该线程池就会创建一个新的线程实例用于执行任务。下面为相关的代码:

protected void doExecute(Runnable task) {    Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));    thread.start();}

而如果想要指定线程池,可以通过在 @Async 注解中的 value 参数中指定所要使用的线程池的 Bean Name 。另一种方法是是一个实现了 AsyncConfigurer 接口或是继承其默认适配器类 AsyncConfigurerSupport 的配置类,这样 @Async 注解的方法就会使用指定的自定义的线程池。

使用@Async注解的话采用的是springBoot默认的线程池,不过一般我们会自定义线程池(因为比较灵活),配置方式有:

  • 使用 xml 文件配置的方式

  • 使用Java代码结合@Configuration进行配置(推荐使用)

下面显示配置线程的代码实现

package com.deppon.ptos.load.config; import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor;import java.util.concurrent.ThreadPoolExecutor; /** * @Description: 异步线程管理 * @Author:   LYH * @CreateDate: 2019/6/27 8:54 * @Version: 1.0 * @JDK: 1.8 */@Configuration@EnableAsync@Slf4jpublic class ExecutorConfig {      @Value("${async.executor.thread.core_pool_size}")    private int corePoolSize;    @Value("${async.executor.thread.max_pool_size}")    private int maxPoolSize;    @Value("${async.executor.thread.queue_capacity}")    private int queueCapacity;    @Value("${async.executor.thread.name.prefix}")    private String namePrefix;     @Bean(name = "asyncServiceExecutor")    public Executor asyncServiceExecutor() {        log.info("start asyncServiceExecutor");        ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();        //配置核心线程数        executor.setCorePoolSize(corePoolSize);        //配置最大线程数        executor.setMaxPoolSize(maxPoolSize);        //配置队列大小        executor.setQueueCapacity(queueCapacity);        //配置线程池中的线程的名称前缀        executor.setThreadNamePrefix(namePrefix);         // rejection-policy:当pool已经达到max size的时候,如何处理新任务        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());        //执行初始化        executor.initialize();        return executor;    }}
package com.deppon.ptos.load.config;  import lombok.extern.slf4j.Slf4j;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.stereotype.Component;import org.springframework.util.concurrent.ListenableFuture; import java.util.concurrent.Callable;import java.util.concurrent.Future;import java.util.concurrent.ThreadPoolExecutor; /** * @Description: 打印异步线程的执行情况   使用Callbale Future 来返回线程的信息 * @Author: 633805  LYH * @CreateDate: 2019/6/27 8:59 * @Version: 1.0 * @JDK: 1.8 */@Component@Slf4jpublic class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {      private void showThreadPoolInfo(String prefix) {        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();         if (null == threadPoolExecutor) {            return;        }         log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",                this.getThreadNamePrefix(),                prefix,                threadPoolExecutor.getTaskCount(),                threadPoolExecutor.getCompletedTaskCount(),                threadPoolExecutor.getActiveCount(),                threadPoolExecutor.getQueue().size());    }     @Override    public void execute(Runnable task) {        showThreadPoolInfo("1. do execute");        super.execute(task);    }     @Override    public void execute(Runnable task, long startTimeout) {        showThreadPoolInfo("2. do execute");        super.execute(task, startTimeout);    }     @Override    public Future submit(Runnable task) {        showThreadPoolInfo("1. do submit");        return super.submit(task);    }     @Override    public  Future submit(Callable task) {        showThreadPoolInfo("2. do submit");        return super.submit(task);    }     @Override    public ListenableFuture submitListenable(Runnable task) {        showThreadPoolInfo("1. do submitListenable");        return super.submitListenable(task);    }     @Override    public  ListenableFuture submitListenable(Callable task) {        showThreadPoolInfo("2. do submitListenable");        return super.submitListenable(task);    }}

使用:

@Async("asyncServiceExecutor")

到这一步,异步就算开启了。

下面主要说一说错误的

使用@Async导致异步不成功的情况

如下方式会使@Async失效

  • 异步方法使用static修饰

  • 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类

  • 异步方法不能与被调用的异步方法在同一个类中

  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象

  • 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

关于springboot @Async 注解如何实现方法异步就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

线程 注解 方法 配置 任务 时候 代码 数据 方式 情况 处理 最大 中指 内容 名称 效率 更多 核心 注释 队列 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技园 广东万易互联网科技有限公司惠州分公司 互联网是第几次科技革命的成果 易互联网科技有限公司 宜安科技 互联网金融 亿账通互联网科技 火传媒上海互联网科技 上海卓越科技 互联网 青岛中康互联网医疗科技有限公司 哈尔滨新华互联网科技学院 华服互联网科技官网 南山科技园互联网公司有哪些 玉溪互联网科技怎么选 深圳市优智互联网科技有限公司 怎样加入科技互联网 工业互联网科技创业 科技互联网行业投资研究 长沙渺峰互联网科技有限公司 科技信息时代互联网发展 广州全民伙伴互联网科技有限公司 互联网络科技有限公司 互联网科技集团 深圳齐家互联网科技 奔汉互联网科技 碳银互联网科技有限公司 狮子座互联网科技培训 剑昆互联网络科技有限公司临桂 互联网科技人工智能实验室 中国互联网公司排名锤子科技 互联网科技的前景
0