1. 定义
当使用Spring框架进行开发时,我们可能会遇到一些耗时的操作,比如发送邮件、调用第三方接口等。如果直接在主线程中执行这些操作,会导致主线程阻塞,影响系统的响应速度,一般会用到多线程来处理,但线程的创建与销毁是一个开销大的操作,因此一般采用创建线程池的方式来维护线程。但项目一般比较复杂,就会存在一个问题,每个开发人员都维护了一套线程池或每个功能模块都维护了线程池,这样就会导致项目中存在多个线程池,由于线程池中的线程数量是根据cpu的核心数来创建的,多个线程池的意义就不大,且维护了多套。
为了解决这个问题,Spring提供了@Async
注解来支持异步执行任务,而且可以统一管理线程池。
2. @Async注解的使用
@Async
注解可以用来修饰方法或类。当修饰方法时,会将该方法标记为一个异步方法,可以在调用时在新的线程中进行执行。当修饰类时,将会对该类的所有方法生效。
2.1. 解析使用
- 使用
@EnableAsync
开启注解支持
- 创建线程池
Executor
,也可以在第3点中new()
出来
- 实现
AsyncConfigurer
,重写getAsyncExecutor
获取线程池方法和getAsyncUncaughtExceptionHandler
处理异常方法
getAsyncExecutor
会返回@Async
需要的线程池,如果为空的话spring则会自行创建一个线程,则相当于没有使用线程池,因此此处需要特别注意
getAsyncUncaughtExceptionHandler
异常处理方法,可以用来记录异步线程失败的处理,如记录日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @Configuration @EnableAsync public class BaseAsyncConfigurer implements AsyncConfigurer {
@Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()+1); executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5); executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*2); executor.setThreadNamePrefix("this-excutor-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (Throwable ex, Method method, Object... params)->{ System.out.println("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName()); System.out.println("type : " + ex.getClass().getName()); System.out.println("exception : " + ex.getMessage()); }; } }
|
使用的方法上直接加上注解@Async
即可
1 2 3 4
| @Async public void sendMessage(){ }
|