在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的。但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务。其实在Spring 3.x之后,就已经内置了@Async来完美解决这个问题。
两个注解:@EnableAysnc、@Aysnc
【1】TaskExecutor
Spring异步线程池的接口类,其实质是java.util.concurrent.Executor。
Spring 已经实现的异常线程池:
① SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
② SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作,只适用于不需要多线程的地方。
③ ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类 。
④ SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类。
⑤ ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装。
【2】@Async注解
源码如下:
/** * Annotation that marks a method as a candidate for <i>asynchronous</i> execution. * // 将方法标记为异步执行 * Can also be used at the type level, in which case all of the type's methods are * considered as asynchronous. *// 也可以在类型级别使用,在这种情况下,所有类型的方法都被认为是异步的。 * <p>In terms of target method signatures, any parameter types are supported. * // 目标方法中,可以支持任何类型的参数 * However, the return type is constrained to either {@code void} or * {@link java.util.concurrent.Future}. * // 然而,返回类型要么是void,要么是Future * In the latter case, you may declare the * more specific {@link org.springframework.util.concurrent.ListenableFuture} or * {@link java.util.concurrent.CompletableFuture} types which allow for richer * interaction with the asynchronous task and for immediate composition with * further processing steps. * * <p>A {@code Future} handle returned from the proxy will be an actual asynchronous * {@code Future} that can be used to track the result of the asynchronous method execution. * // 代理返回的Future可以用来跟踪异步方法处理的结果 * However, since the target method needs to implement the same signature, * it will have to return a temporary {@code Future} handle that just passes a value * through: e.g. Spring's {@link AsyncResult}, EJB 3.1's {@link javax.ejb.AsyncResult}, * or {@link java.util.concurrent.CompletableFuture#completedFuture(Object)}. * * @author Juergen Hoeller * @author Chris Beams * @since 3.0 * @see AnnotationAsyncExecutionInterceptor * @see AsyncAnnotationAdvisor */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Async { /** * A qualifier value for the specified asynchronous operation(s). * <p>May be used to determine the target executor to be used when executing this * method, matching the qualifier value (or the bean name) of a specific * {@link java.util.concurrent.Executor Executor} or * {@link org.springframework.core.task.TaskExecutor TaskExecutor} * bean definition. * <p>When specified on a class level {@code @Async} annotation, indicates that the * given executor should be used for all methods within the class. Method level use * of {@code Async#value} always overrides any value set at the class level. * @since 3.1.2 */ String value() default ""; }
【3】无返回值代码示例
Service如下:
@Service public class AsyncService { @Async public void hello(){ System.out.println("进入service。。。"); try { Thread.sleep(3000); System.out.println("3S后数据开始处理中。。"); } catch (InterruptedException e) { e.printStackTrace(); } } }
Controller如下:
@RestController public class AsyncController { @Autowired AsyncService asyncService; @GetMapping("/hello") public String hello(){ System.out.println("进入Controller。。。"); asyncService.hello(); return "success"; } }
Service的方法上使用了@Async注解,如果使该注解起作用,则需要在主程序上添加@EnableAsync注解。
@SpringBootApplication @EnableAsync public class SpringBoot01CacheApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot01CacheApplication.class, args); } }
浏览器发起请求,控制台打印如下:
进入Controller。。。 2018-07-08 11:10:30.305 INFO 3996 --- [io-8080-exec-10] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either 进入service。。。 3S后数据开始处理中。。
【4】使用Future获取异步方法返回值
Service如下:
/** * 异步调用返回Future * * @param i * @return */ @Async public Future<String> asyncInvokeReturnFuture(int i) { System.out.println("进入asyncInvokeReturnFuture..."); Future<String> future; try { Thread.sleep(3000); System.out.println("3S后asyncInvokeReturnFuture数据开始处理中。。"); future = new AsyncResult<String>("success:" + i); } catch (InterruptedException e) { future = new AsyncResult<String>("error"); } return future; }
Controller修改如下:
@GetMapping("/hello") public String hello(){ System.out.println("进入Controller。。。"); asyncService.hello(); Future<String> future=asyncService.asyncInvokeReturnFuture(300); String s = null; try { s = future.get(); } catch (Exception e){ e.printStackTrace(); } System.out.println("异步方法返回值 : "+s); return s; } }
控制台打印如下:
进入Controller。。。 2018-07-08 11:42:55.660 INFO 8152 --- [nio-8080-exec-2] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either 进入service.hello()。。。 3S后hello数据开始处理中。。 进入asyncInvokeReturnFuture... 3S后asyncInvokeReturnFuture数据开始处理中。。 异步方法返回值 : success:300
【5】配置自定义线程池
源码示例如下:
@Configuration public class MyExecutorConfig { /** * 自定义异步线程池 * @return */ @Bean public AsyncTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setThreadNamePrefix("Anno-Executor"); executor.setMaxPoolSize(100); // 设置拒绝策略 executor.setRejectedExecutionHandler(new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // ..... } }); // 使用预定义的异常处理类 // executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
修改service再次测试如下:
说明使用了自定义异步线程池!