原来你是这样的SpringBoot--Async异步任务
时间:2023-08-27 16:06:37
本节我们一起学习一下SpringBoot中的异步调用,主要用于优化耗时较长的操作,提高系统性能和吞吐量。
一、新建项目,启动异步调用
首先给启动类增加注解@EnableAsync,支持异步调用
(资料图)
@EnableAsync@SpringBootApplicationpublic class CathySpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(CathySpringbootDemoApplication.class, args); }}
然后定义要执行的Task,分类增加一个同步方法和异步方法,其中异步方法需要增加注解@Async
@Componentpublic class AsyncTask { /** * 异步任务,需要注解@Async * * @param taskId 任务编号id * @param second 执行时长,模拟慢任务 * @return */ @Async public Future 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 f1 = asyncTask.asyncExec(1, 3L); Future f2 = asyncTask.asyncExec(2, 3L); Future 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> list = new ArrayList<>(); for (int i = 0; i < 20; i++) { Future 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 asyncExec(int taskId, Long second) { exec(taskId, second); return new AsyncResult<>(Boolean.TRUE); }
执行效果如下:
可以看出,线程池设置的参数已经生效。