@EnableAsync@Async使用总结

摘要:
只要需要@EnableAsync,就可以使用多线程。如果两者都无法解析,SimpleAsyncTaskExecutor将用于处理异步方法调用。定义配置类@Configuration@EnableAsyncpublicclassThreadPoolTaskConfig{privatestaticfinalintcorePoolSize=10;//核心线程数privatestaticinalinmaxPoolSize=100;//最大线程数privatestaticfinalinkeepAliveTime=10;//Allow thread idle time privatestaticfinalintqueueCapacity=200;//缓冲区队列数privatestaticfinalStringthreadNamePrefix=“异步服务-” ;// 线程池前缀@Bean//Bean的名称,默认值是方法名publicThreadPoolTaskExecutorAsyncExecutor(){ThreadPoolTaskExecutiorexecutor=newThreadPoolTaskExecutor(; executor.setCorePoolSize;executor.setMaxPoolSize;executor.setQueueCapacity;executor.setKeepAliveSeconds;executor.setThreadNamePrefix//线程池拒绝任务executor.setRejectedExecutionHandler的处理策略//初始化执行器。初始化ze();returnexecutor;}}@配置用于定义配置类。注释类包含一个或多个@Bean注释的方法。这些方法将由AnnotationConfigApplicationContext或AnnotationConfigurationWebApplicationContext类扫描,并用于构建bean定义和初始化Spring容器。将Async方法调用的方法上的@Transactional标记为有效。

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

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

定义配置类

@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;
	}
}

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

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

测试service

@Service
public class testAsyncService {
	Logger log = LoggerFactory.getLogger(testAsyncService.class);
 
	// 发送提醒短信 1
	@Async("taskExecutor")
	public void service1() throws InterruptedException {
		log.info("--------start-service1------------");
		Thread.sleep(5000); // 模拟耗时
	    log.info("--------end-service1------------");
	}
	
	// 发送提醒短信 2
	@Async("taskExecutor")
	public void service2() throws InterruptedException {
		
		log.info("--------start-service2------------");
		Thread.sleep(2000); // 模拟耗时
	    log.info("--------end-service2------------");
 
	}
}

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

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

--------start-service1------------

--------start-service2------------

--------end-service2------------

--------end-service1------------

可以说明我们的异步运行成功了

如下方式会使@Async失效
一、异步方法使用static修饰
二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
三、异步方法不能与异步方法在同一个类中
四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
六、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
七、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用!!!!!!!
八、使用@Async时要求是不能有返回值的不然会报错的 因为异步要求是不关心结果的

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

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {

     @Override
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.initialize();
         return executor;
     }

     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new MyAsyncUncaughtExceptionHandler();
     }
}

免责声明:文章转载自《@EnableAsync@Async使用总结》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇kafka消息的分发与消费图形化显示 Python 函数之间的调用关系下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Spring中单例和多例模式

Spring容器管理的bean在默认情况下是单例的,也是一个bean只会创建一个对象,存在内置 map中,之后无论获取多少次该bean,都返回同一个对象。这样可以减小了对象的创建,从而减小了内存的开销。 bean在单例或多例模式下的生命周期: 单例模式 bean在单例模式下,spring容器启动时解析xml文件发现该bean标签后,直接创建该bean对象...

C#多线程和异步(一)——基本概念和使用方法

阅读目录 一、多线程相关的基本概念 二、C#中的线程使用 2.1  基本使用 2.2  常用的属性和方法 2.3  线程同步 2.4  跨线程访问 回到顶部 一、多线程相关的基本概念 进程(Process):是系统中的一个基本概念。 一个正在运行的应用程序在操作系统中被视为一个进程,包含着一个运行程序所需要的资源,进程可以包括一个或多...

深度剖析OpenGL ES中的多线程和多窗口渲染技术

由 创新网小编 于 星期五, 2014-04-11 14:56 发表 移动设备中的CPU和GPU已经变得很强大,到处都是配备一个或多个高分辨率屏幕的设备,需要使用带有图形驱动器的复杂交互也日益增加。在这篇博客文章中,我将讨论多线程和多窗口渲染对开发人员来讲意味着什么,同时我将介绍将这些技术应用您设计当中的条件和时机。 什么是多线程渲染? 传统上,Ope...

c#之多线程之为所欲为

一 什么是多线程 1、 什么是进程?一个 exe 运行一次就会产生一个进程,一个 exe 的多个进程之 间数据互相隔离。 2、 一个进程里至少有一个线程:主线程。我们平时写的控制台程序默认就是单线程的,代 码从上往下执行,一行执行完了再执行下一行; 3、 什么是多线程:一个人两件事情同时做效率高。同一时刻一 个人只能干一件事情,其实是在“快速频繁切换”,如...

SpringBoot启动过程解析(简化)

springBoot web方式启动过程 在这个启动过程中会有各种SpringBoot对外提供的扩展接口来对不同启动阶段进行自定义操作。 了解启动过程也是为了让我们更好理解SpringBoot提供的扩展接口使用   jar包启动或者外置war包启动都是调用SpringApplication.run()方法进行项目启动 tomcat会查询context上下文...

java多线程案例

packagecom.alibaba.yuntu.me.biz.district.service.impl.MyUtis; importcom.alibaba.fastjson.JSONObject; importcom.alibaba.yuntu.me.common.base.util.HttpUtil; importlombok.SneakyThro...