【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();}
}

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...