Spring @Async開啓異步任務

1. 開啓異步

@SpringBootApplication
@EnableAsync        //開啓異步任務
public class Application {
    @Bean(name="processExecutor")
    public TaskExecutor workExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix("Async-");
        threadPoolTaskExecutor.setCorePoolSize(10);
        threadPoolTaskExecutor.setMaxPoolSize(20);
        threadPoolTaskExecutor.setQueueCapacity(600);
        threadPoolTaskExecutor.afterPropertiesSet();

        // 自定義拒絕策略
        threadPoolTaskExecutor.setRejectedExecutionHandler((r, executor) -> {
            // .....
        });
        // 使用預設的拒絕策略
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return threadPoolTaskExecutor;
    }




    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 配置線程池

Spring異步線程池的接口類,其實質是java.util.concurrent.Executor。

Spring 已經實現的異常線程池:
1. SimpleAsyncTaskExecutor:
不是真的線程池,這個類不重用線程,每次調用都會創建一個新的線程。
2. SyncTaskExecutor:
這個類沒有實現異步調用,只是一個同步操作。只適用於不需要多線程的地方
3. ConcurrentTaskExecutor:
Executor的適配類,不推薦使用。如果ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類
4. SimpleThreadPoolTaskExecutor:
是Quartz的SimpleThreadPool的類。線程池同時被quartz和非quartz使用,才需要使用此類
5. ThreadPoolTaskExecutor:
最常使用,推薦。其實質是對java.util.concurrent.ThreadPoolExecutor的包裝。

3. 添加@Async註解

    /**
     * 異步調用返回Future
     * 
     * @param i
     * @return
     */
    @Async
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture, parementer={}", i);
        Future<String> future;
        try {
            Thread.sleep(1000 * 1);
            future = new AsyncResult<String>("success:" + i);
        } catch (InterruptedException e) {
            future = new AsyncResult<String>("error");
        }
        return future;
    }

4. 通過XML文件配置

    <!-- 等價於 @EnableAsync, executor指定線程池 -->
    <task:annotation-driven executor="xmlExecutor"/>
    <!-- id指定線程池產生線程名稱的前綴 -->
    <task:executor
        id="xmlExecutor"
        pool-size="5-25"
        queue-capacity="100"
        keep-alive="120"
        rejection-policy="CALLER_RUNS"/>

5. 異常處理

在調用方法時,可能出現方法中拋出異常的情況。在異步中主要有有兩種異常處理方法:
1. 對於方法返回值是Futrue的異步方法:
a) 一種是在調用future的get時捕獲異常;
b) 在異常方法中直接捕獲異常
2. 對於返回值是void的異步方法:
通過AsyncUncaughtExceptionHandler處理異常

/**
 * 通過實現AsyncConfigurer自定義線程池,包含異常處理
 */
@Service
public class MyAsyncConfigurer implements AsyncConfigurer{
    private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class);

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();  
        threadPool.setCorePoolSize(1);  
        threadPool.setMaxPoolSize(1);  
        threadPool.setWaitForTasksToCompleteOnShutdown(true);  
        threadPool.setAwaitTerminationSeconds(60 * 15);  
        threadPool.setThreadNamePrefix("MyAsync-");
        threadPool.initialize();
        return threadPool;  
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new MyAsyncExceptionHandler();  
    }

    /**
     * 自定義異常處理類
     */
    class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {  

        @Override  
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {  
            log.info("Exception message - " + throwable.getMessage());  
            log.info("Method name - " + method.getName());  
            for (Object param : obj) {  
                log.info("Parameter value - " + param);  
            }  
        }  

    } 

}

6. 參考文章

[1] Spring Boot系列二 Spring @Async異步線程池用法總結

[2] Spring Boot開啓異步任務 子線程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章