@Async注解
Spring3开始提供了@Async注解,该注解能够标注在办法或者类上,从而能够不便的实现办法的异步调用。调用者在调用异步办法时将立刻返回,办法的理论执行将提交给指定的线程池中的线程执行。
@Async注意事项:
- @Async标注在类上时,示意该类的所有办法都是异步办法。
- @Async注解的办法肯定要通过依赖注入调用(因为要通过代理对象调用),不能间接通过this对象调用,否则不失效。
@Async应用示例
1、Spring中启用@Async
创立一个配置类,并加上@EnableAsync注解即可
@Configuration@EnableAsyncpublic class SpringAsyncConfig{}
2、应用@Async
创立异步办法执行类
@Servicepublic class AsyncService { // 无返回值的异步办法 @Async public void noReturnMethod() { String tName = Thread.currentThread().getName(); System.out.println("current thread name : " + tName); System.out.println("noReturnMethod end"); } // 有返回值的异步办法 @Async public Future<String> withReturnMethod() { String tName = Thread.currentThread().getName(); System.out.println("current thread name : " + tName); return new AsyncResult<>("aaa"); }}
创立调用异步办法的类
@RestController@RequestMapping("/api/async/test/")public class AsyncController { @Autowired AsyncService asyncService; // 无返回值 @GetMapping("/noReturn") public String noReturn() { asyncService.noReturnMethod(); return "success"; } // 有返回值 @GetMapping("/withReturn") public String withReturn() { Future<String> future = asyncService.withReturnMethod(); try { String res = future.get();// 阻塞获取返回值 System.out.println("res = " + res); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return "success"; }}
Spring定义的线程池类
Spring 曾经定义的线程池类有如下一些:
- SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,默认每次调用都会创立一个新的线程。
- SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只实用于不须要多线程的中央。
- ConcurrentTaskExecutor:Executor的适配类,不举荐应用。如果ThreadPoolTaskExecutor不满足要求时,才用思考应用这个类。
- SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz应用,才须要应用此类。
- ThreadPoolTaskExecutor :最常应用,举荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装。
配置自定义线程池
异步办法默认的线程池
在@EnableAsync注解中有如下正文阐明:
By default, Spring will be searching for an associated thread pool definition:either a unique {@link org.springframework.core.task.TaskExecutor} bean in the context,or an {@link java.util.concurrent.Executor} bean named "taskExecutor" otherwise. Ifneither of the two is resolvable, a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}will be used to process async method invocations.
翻译一下就是:
Spring首先会通过上面两种形式查找作为异步办法的默认线程池:
1、查找惟一的一个TaskExecutor类型的bean
2、或者是一个名称为“taskExecutor”的Executor类型的Bean。
如果下面两种形式都没有查找到,则应用SimpleAsyncTaskExecutor作为异步办法的默认线程池
而SimpleAsyncTaskExecutor线程池去执行@Async标注的异步办法,因为该线程池不会重用线程,所以我的项目中举荐应用自定义的线程池。
配置异步办法默认自定义线程池
配置@Async默认的线程池有多种形式:
- 从新实现接口AsyncConfigurer
- 继承AsyncConfigurerSupport
- 自定义一个TaskExecutor类型的bean。
- 自定义一个名称为“taskExecutor”的Executor类型的Bean。
上面展现了通过形式1(从新实现接口AsyncConfigurer)来配置默认的自定义线程池:
// 配置类实现AsyncConfigurer接口的getAsyncExecutor()办法@Configuration@EnableAsyncpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3);//外围池大小 executor.setMaxPoolSize(6);//最大线程数 executor.setKeepAliveSeconds(60);//线程闲暇工夫 executor.setQueueCapacity(10);//队列水平 executor.setThreadNamePrefix("my-executor1-");//线程前缀名称 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置回绝策略 executor.setAllowCoreThreadTimeOut(true);// 容许销毁外围线程 executor.initialize(); return executor; }}
不同异步办法配置不同线程池
有时候不同性能的异步办法须要配置不同的线程池,能够通过在@Async上指定线程池的名称来实现
@Configurationpublic class ExecutorConfig { @Bean("customExecutor-1")// 自定义线程池1 public Executor customExecutor1() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3);//外围池大小 executor.setMaxPoolSize(6);//最大线程数 executor.setKeepAliveSeconds(60);//线程闲暇工夫 executor.setQueueCapacity(10);//队列水平 executor.setThreadNamePrefix("customExecutor-1-");//线程前缀名称 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置回绝策略 executor.setAllowCoreThreadTimeOut(true);// 容许销毁外围线程 executor.initialize(); return executor; } @Bean("customExecutor-2")// 自定义线程池2 public Executor customExecutor2() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3);//外围池大小 executor.setMaxPoolSize(6);//最大线程数 executor.setKeepAliveSeconds(60);//线程闲暇工夫 executor.setQueueCapacity(10);//队列水平 executor.setThreadNamePrefix("customExecutor-2-");//线程前缀名称 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置回绝策略 executor.setAllowCoreThreadTimeOut(true);// 容许销毁外围线程 executor.initialize(); return executor; }}
@Async("customExecutor-1")public void method1(){}@Async("customExecutor-2")public void method2(){}
@Async的异样解决
当办法是带Future返回值的时候,Future.get()办法会抛出异样,所以异样捕捉是没问题的。然而当办法是不带返回值的时候,那么此时主线程就不能捕捉到异样,须要额定的配置来解决异样,能够有上面两种形式。
1、通过try-catch解决异样
间接在异步办法中应用try-catch来解决抛出的异样。这个办法也能够用于带Future返回值的异步办法。
2、通过实现AsyncUncaughtExceptionHandler接口
@Configuration@EnableAsyncpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { // 省略自定义线程池的代码 } // 自定义异样解决 @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncUncaughtExceptionHandler() { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... objects) { System.out.println(method.getName() + "产生异样!异样起因:" + throwable.getMessage() ); } }; }}
参考资料
- Spring应用@Async注解