【Java】@EnableAsync@Async使用总结
创始人
2024-06-02 20:05:42
0

【Java】@EnableAsync@Async使用总结

在使用多线程的时候,往往需要继承Thread类,或者实现Runnable接口,如果要使用到线程池,还需要来创建Executors,在Spring中已经做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过Spring提供的ThreadPoolTaskExecutor就可以使用线程池。

默认情况下,Spring将搜索相关的线程池定义:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。

配置类

@Configuration:用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器;

@EnableAsync:开始对异步任务的支持。

package cn.com.codingce.demo.config;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.ThreadPoolExecutor;/*** @author ma*/
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {/*** 核心线程数(默认线程数)*/private static final int corePoolSize = 10;/*** 最大线程数*/private static final int maxPoolSize = 100;/*** 允许线程空闲时间(单位:默认为秒)*/private static final int keepAliveTime = 10;/*** 缓冲队列数*/private static final int queueCapacity = 200;/*** 线程池名前缀*/private static final String threadNamePrefix = "Async-Service-";@Bean("taskExecutor") // bean的名称, 默认为首字母小写的方法名public ThreadPoolTaskExecutor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveTime);executor.setThreadNamePrefix(threadNamePrefix);// 线程池对拒绝任务的处理策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 初始化executor.initialize();return executor;}}

测试

IndexController

package cn.com.codingce.demo.conrtoller;import cn.com.codingce.demo.service.IndexServiceOne;
import cn.com.codingce.demo.service.IndexServiceTwo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author mxz*/
@RestController
@RequestMapping("index")
public class IndexController {@Autowiredprivate IndexServiceOne indexServiceOne;@Autowiredprivate IndexServiceTwo indexServiceTwo;/*** default*/@GetMapping(value = "/default", produces = "text/html;charset=utf-8")@ApiOperation(value = "default")public String getDefault() throws InterruptedException {indexServiceOne.service1();indexServiceTwo.service2();return "服务运行正常...";}}

IndexServiceOne

package cn.com.codingce.demo.service;public interface IndexServiceOne {void service1();}

IndexServiceOneImpl

package cn.com.codingce.demo.service.impl;import cn.com.codingce.demo.service.IndexServiceOne;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;/*** @author ma*/
@Service("indexServiceOne")
@Slf4j
public class IndexServiceOneImpl implements IndexServiceOne {/*** 发送提醒短信 1*/@Override@Async("taskExecutor")public void service1() {try {log.info("--------start-service1------------");// 模拟耗时Thread.sleep(5000);log.info("--------end-service1------------");} catch (Exception e) {log.error("--------error------------");}}}

IndexServiceTwo

package cn.com.codingce.demo.service;public interface IndexServiceTwo {void service2();}

IndexServiceTwoImpl

package cn.com.codingce.demo.service.impl;import cn.com.codingce.demo.service.IndexServiceTwo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;/*** @author ma*/
@Service("indexServiceTwo")
@Slf4j
public class IndexServiceTwoImpl implements IndexServiceTwo {/*** 发送提醒短信 2*/@Override@Async("taskExecutor")public void service2() {try {log.info("--------start-service2------------");// 模拟耗时Thread.sleep(1000);log.info("--------end-service2------------");} catch (Exception e) {log.error("--------error------------");}}}

@Async注解来声明一个或多个异步任务,可以加在方法或者类上,加在类上表示这整个类都是使用这个自定义线程池进行操作

接着我们可以创建controller类@Autowired这个service并且调用这其中两个方法,进行连续调用,会发现运行结果是

2023-03-13 12:39:24.653  INFO 21008 --- [Async-Service-1] c.c.c.d.s.impl.IndexServiceOneImpl       : --------start-service1------------
2023-03-13 12:39:24.653  INFO 21008 --- [Async-Service-2] c.c.c.d.s.impl.IndexServiceTwoImpl       : --------start-service2------------
2023-03-13 12:39:25.660  INFO 21008 --- [Async-Service-2] c.c.c.d.s.impl.IndexServiceTwoImpl       : --------end-service2------------
2023-03-13 12:39:29.655  INFO 21008 --- [Async-Service-1] c.c.c.d.s.impl.IndexServiceOneImpl       : --------end-service1------------

@Async失效排查

1、异步方法使用static修饰;
2、异步类没有使用@Component注解(或其他注解)导致Spring无法扫描到异步类;
3、异步方法不能与异步方法在同一个类中;
4、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象;
5、如果使用Spring Boot框架必须在启动类中增加@EnableAsync注解;
6、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效;
7、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用!;
8、使用@Async时要求是不能有返回值的不然会报错的 因为异步要求是不关心结果的。

Other

关于线程池的配置还有一种方式,就是直接实现AsyncConfigurer接口,重写getAsyncExecutor方法即可,代码如下:

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(7);executor.setMaxPoolSize(42);executor.setQueueCapacity(11);executor.setThreadNamePrefix("MyExecutor-");executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new MyAsyncUncaughtExceptionHandler();}
}

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...