1. @Async
在spring中,可以通過@EnableAsync + @Async兩個註解非常快捷的實現異步。步驟如下:
啓動類加上: @EnableAsync註解 並且在service上加上@Async註解
@SpringBootApplication(
exclude = {CodecsAutoConfiguration.class},
scanBasePackages = {
"com.arvato.config",
"com.arvato.service",
"com.arvato.controller"
})
@EnableAsync
@MapperScan(basePackages = "com.arvato.mapper.config")
public class WebFluxApplication {
public static void main(String[] args) {
SpringApplication.run(WebFluxApplication.class, args);
}
}
@RestController
@RequestMapping("/wxwork/sync")
public class WxworkSyncController {
@Autowired
private WxworkSyncService wxworkSyncService;
@GetMapping
public Mono<String> sync() {
// 異步處理業務
wxworkSyncService.sync();
return Mono.just("直接返回處理成功");
}
}
@Service
public class WxworkSyncService {
@Async
public void sync() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName());
}
}
然後瘋狂發請求測試異步情況,並且打印線程名。我們發現默認情況下,每一次調用都是開啓一個新的線程,截圖如下:
可以看出來,@Async用的是SimpleAsyncTaskExecutor線程池,但是如果沒有對SimpleAsyncTaskExecutor做策略配置的話,是不復用線程的,這是對服務器資源的浪費。
2.自定義線程池
自定義線程池很簡單,只要實現AsyncConfigurer接口,並且重寫getAsyncExecutor方法。
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
@Configuration
@EnableAsync(proxyTargetClass = true)
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) ->
log.error("Unexpected error occurred invoking async method: " + method +
", args: " + Arrays.toString(params), ex);
}
/**
* 自定義異步線程池
* @return executor
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("MyExecutor-");
executor.setWaitForTasksToCompleteOnShutdown(false);
// 設置拒絕策略
executor.setRejectedExecutionHandler((r, e) -> {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
});
executor.initialize();
return executor;
}
}
再次發請求測試: