在實際開發場景中,不需要等待某個方法執行完成而繼續往后執行,那么我們可以將這個方法加上@Async注解放入后台線程(或線程池)中異步執行。簡單示例代碼如下:
先使用@EnableAsync來開啟異步的支持,配置一個線程池:
@Configuration @EnableAsync public class ThreadPoolConfig { private static int corePoolSize=30; private static int maxPoolSize=100; private static int queueCapacity=100; private static int keepAliveSeconds=300; @Bean public TaskExecutor jobExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設置核心線程數 executor.setCorePoolSize(corePoolSize); // 設置最大線程數 executor.setMaxPoolSize(maxPoolSize); // 設置隊列容量 executor.setQueueCapacity(queueCapacity); // 設置線程活躍時間(秒) executor.setKeepAliveSeconds(keepAliveSeconds); // 設置默認線程名稱 executor.setThreadNamePrefix("async-job-thread-"); // 設置拒絕策略rejection-policy:當pool已經達到max size的時候,如何處理新任務 CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務結束后再關閉線程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
然后在指定需要異步執行方法上加入@Async注解,並自定線程池(當然可以不指定,直接寫@Async)
@Async("jobExecutor") public void asyncUpdateOrders(){ logger.info(Thread.currentThread().getName()+"異步執行"); }
程序執行入口主程序:
@RequestMapping(value = "/asyncUpdateOrders") @ResponseBody public String asyncUpdateOrders(HttpServletRequest request) { try { logger.info(Thread.currentThread().getName()+"主線程請求異步執行asyncUpdateOrders"); ordersService.asyncUpdateOrders(); logger.info(Thread.currentThread().getName()+"主線程請求異步執行asyncUpdateOrders結束"); } catch (Exception e) { logger.error(e.getMessage(), e); return "false"; } return "true"; }
執行結果:
2020-06-23 15:18:59.363 [] [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet :Completed initialization in 10 ms 2020-06-23 15:18:59.396 [] [http-nio-8080-exec-1] INFO c.y.p.w.c.OrderProcessController :http-nio-8080-exec-1主線程請求異步執行asyncUpdateOrders 2020-06-23 15:18:59.404 [] [http-nio-8080-exec-1] INFO c.y.p.w.c.OrderProcessController :http-nio-8080-exec-1主線程請求異步執行asyncUpdateOrders結束 2020-06-23 15:18:59.404 [] [async-job-thread-1] INFO c.y.p.d.s.impl.OrdersServiceImpl :async-job-thread-1異步執行
直接寫@Async不指定線程池時,如果線程池配置只配了上面jobExecutor一種,則會默認使用該線程池執行,結果和上面一樣,如果線程池配置配置了多個線程池,則此時不指定線程池時則會使用系統默認的SimpleAsyncTaskExecutor線程執行,結果如下:
2020-06-23 15:23:38.071 [] [http-nio-8080-exec-1] INFO c.y.p.w.c.OrderProcessController :http-nio-8080-exec-1主線程請求異步執行asyncUpdateOrders 2020-06-23 15:23:38.077 [] [http-nio-8080-exec-1] INFO o.s.s.a.AnnotationAsyncExecutionInterceptor :More than one TaskExecutor bean found within the context,
and none is named 'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly as an alias) in order to use it for async
processing: [jobExecutor, jobBBExecutor] 2020-06-23 15:23:38.079 [] [http-nio-8080-exec-1] INFO c.y.p.w.c.OrderProcessController :http-nio-8080-exec-1主線程請求異步執行asyncUpdateOrders結束 2020-06-23 15:23:38.079 [] [SimpleAsyncTaskExecutor-1] INFO c.y.p.d.s.impl.OrdersServiceImpl :SimpleAsyncTaskExecutor-1異步執行