@EnableAsync@Async使用总结

2022年01月15日 阅读数:3
这篇文章主要向大家介绍@EnableAsync@Async使用总结,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

咱们在使用多线程的时候,每每须要建立Thread类,或者实现Runnable接口,若是要使用到线程池,咱们还须要来建立Executors,在使用spring中,已经给咱们作了很好的支持。只要要@EnableAsync就能够使用多线程。使用@Async就能够定义一个线程任务。经过spring给咱们提供的ThreadPoolTaskExecutor就能够使用线程池。java

默认状况下,Spring将搜索相关的线程池定义:要么在上下文中搜索惟一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。若是二者都没法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。spring

定义配置类

@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而且调用这其中两个方法,进行连续调用,会发现运行结果是ide

--------start-service1------------测试

--------start-service2------------线程

--------end-service2------------code

--------end-service1------------对象

能够说明咱们的异步运行成功了

以下方式会使@Async失效
1、异步方法使用static修饰
2、异步类没有使用@Component注解(或其余注解)致使spring没法扫描到异步类
3、异步方法不能与异步方法在同一个类中
4、类中须要使用@Autowired或@Resource等注解自动注入,不能本身手动new对象
5、若是使用SpringBoot框架必须在启动类中增长@EnableAsync注解
6、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
7、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中否则不会起做用!!!!!!!
8、使用@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();
     }
}