本節我們一起學習一下SpringBoot中的非同步調用,主要用於優化耗時較長的操作,提高系統性能和吞吐量。 # 一、新建項目,啟動非同步調用 首先給啟動類增加註解@EnableAsync,支持非同步調用 ``` @EnableAsync @SpringBootApplication public clas ...
本節我們一起學習一下SpringBoot中的非同步調用,主要用於優化耗時較長的操作,提高系統性能和吞吐量。
一、新建項目,啟動非同步調用
首先給啟動類增加註解@EnableAsync,支持非同步調用
@EnableAsync
@SpringBootApplication
public class CathySpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CathySpringbootDemoApplication.class, args);
}
}
然後定義要執行的Task,分類增加一個同步方法和非同步方法,其中非同步方法需要增加註解@Async
@Component
public class AsyncTask {
/**
* 非同步任務,需要註解@Async
*
* @param taskId 任務編號id
* @param second 執行時長,模擬慢任務
* @return
*/
@Async
public Future<Boolean> asyncExec(int taskId, Long second) {
exec(taskId, second);
return new AsyncResult<>(Boolean.TRUE);
}
public void exec(int taskId, Long second) {
System.out.println("開始執行任務" + taskId);
try {
Thread.sleep(second * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("結束執行任務" + taskId);
}
}
其實接下來就可以在controller中創建介面來進行簡單的測試了
@RestController
@RequestMapping("/async")
public class AsyncController {
@Autowired
AsyncTask asyncTask;
@GetMapping("sync_task")
public String syncTask() {
long start = System.currentTimeMillis();
asyncTask.exec(1, 3L);
asyncTask.exec(2, 3L);
asyncTask.exec(3, 3L);
long time = System.currentTimeMillis() - start;
return "同步執行,耗時" + time;
}
@GetMapping("async_task")
public String asyncTask() {
long start = System.currentTimeMillis();
Future<Boolean> f1 = asyncTask.asyncExec(1, 3L);
Future<Boolean> f2 = asyncTask.asyncExec(2, 3L);
Future<Boolean> f3 = asyncTask.asyncExec(3, 3L);
try {
f1.get();
f2.get();
f3.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
long time = System.currentTimeMillis() - start;
return "非同步執行,耗時" + time;
}
}
啟動程式,查看介面響應結果:
http://localhost:16001/async/sync_task
http://localhost:16001/async/async_task
註意:非同步方法和調用一定要寫在不同的類中
二、線程池配置
上面的例子,在耗時服務多的情況下,使用非同步方法確實提高了響應速度。但是它預設啟用的是Spring預設的線程池SimpleAsyncTaskExecutor,不太靈活。我們把非同步請求多增加幾次調用看看效果:
@GetMapping("async_task")
public String asyncTask() {
long start = System.currentTimeMillis();
List<Future<Boolean>> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Future<Boolean> fi = asyncTask.asyncExec(i, 10L);
list.add(fi);
}
for (int i = 0; i < 20; i++) {
list.forEach(x -> {
try {
x.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
});
}
long time = System.currentTimeMillis() - start;
return "非同步執行,耗時" + time;
}
從上面的運行效果來看,一旦超過8個並行執行的任務,就開始出現等待了。
接下來,我們自定義線程池
@Bean
public TaskExecutor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(16);
executor.setQueueCapacity(20);
executor.setKeepAliveSeconds(30);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("task-thread-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
executor.initialize();
return executor;
}
然後在非同步方法的註解中,明確指定所使用的線程池
@Async("threadPoolTaskExecutor")
public Future<Boolean> asyncExec(int taskId, Long second) {
exec(taskId, second);
return new AsyncResult<>(Boolean.TRUE);
}
執行效果如下:
可以看出,線程池設置的參數已經生效。
本人公眾號[ 敬YES ]同步更新,歡迎大家關註~
作者:陳敬(公眾號:敬姐嘚啵嘚)
出處:http://www.cnblogs.com/janes/
博客文章僅供交流學習,請勿用於商業用途。如需轉載,請務必註明出處。