原来你是这样的SpringBoot--Async异步任务

打印 上一主题 下一主题

主题 846|帖子 846|积分 2538

本节我们一起学习一下SpringBoot中的异步调用,主要用于优化耗时较长的操作,提高系统性能和吞吐量。
一、新建项目,启动异步调用

首先给启动类增加注解@EnableAsync,支持异步调用
  1. @EnableAsync
  2. @SpringBootApplication
  3. public class CathySpringbootDemoApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(CathySpringbootDemoApplication.class, args);
  6.     }
  7. }
复制代码
然后定义要执行的Task,分类增加一个同步方法和异步方法,其中异步方法需要增加注解@Async
  1. @Component
  2. public class AsyncTask {
  3.     /**
  4.      * 异步任务,需要注解@Async
  5.      *
  6.      * @param taskId 任务编号id
  7.      * @param second 执行时长,模拟慢任务
  8.      * @return
  9.      */
  10.     @Async
  11.     public Future<Boolean> asyncExec(int taskId, Long second) {
  12.         exec(taskId, second);
  13.         return new AsyncResult<>(Boolean.TRUE);
  14.     }
  15.     public void exec(int taskId, Long second) {
  16.         System.out.println("开始执行任务" + taskId);
  17.         try {
  18.             Thread.sleep(second * 1000);
  19.         } catch (InterruptedException e) {
  20.             throw new RuntimeException(e);
  21.         }
  22.         System.out.println("结束执行任务" + taskId);
  23.     }
  24. }
复制代码
其实接下来就可以在controller中创建接口来进行简单的测试了
  1. @RestController
  2. @RequestMapping("/async")
  3. public class AsyncController {
  4.     @Autowired
  5.     AsyncTask asyncTask;
  6.     @GetMapping("sync_task")
  7.     public String syncTask() {
  8.         long start = System.currentTimeMillis();
  9.         asyncTask.exec(1, 3L);
  10.         asyncTask.exec(2, 3L);
  11.         asyncTask.exec(3, 3L);
  12.         long time = System.currentTimeMillis() - start;
  13.         return "同步执行,耗时" + time;
  14.     }
  15.     @GetMapping("async_task")
  16.     public String asyncTask() {
  17.         long start = System.currentTimeMillis();
  18.         Future<Boolean> f1 = asyncTask.asyncExec(1, 3L);
  19.         Future<Boolean> f2 = asyncTask.asyncExec(2, 3L);
  20.         Future<Boolean> f3 = asyncTask.asyncExec(3, 3L);
  21.         try {
  22.             f1.get();
  23.             f2.get();
  24.             f3.get();
  25.         } catch (InterruptedException e) {
  26.             throw new RuntimeException(e);
  27.         } catch (ExecutionException e) {
  28.             throw new RuntimeException(e);
  29.         }
  30.         long time = System.currentTimeMillis() - start;
  31.         return "异步执行,耗时" + time;
  32.     }
  33. }
复制代码
启动程序,查看接口响应结果:
http://localhost:16001/async/sync_task

http://localhost:16001/async/async_task

注意:异步方法和调用一定要写在不同的类中
二、线程池配置

上面的例子,在耗时服务多的情况下,使用异步方法确实提高了响应速度。但是它默认启用的是Spring默认的线程池SimpleAsyncTaskExecutor,不太灵活。我们把异步请求多增加几次调用看看效果:
  1. @GetMapping("async_task")
  2.     public String asyncTask() {
  3.         long start = System.currentTimeMillis();
  4.         List<Future<Boolean>> list = new ArrayList<>();
  5.         for (int i = 0; i < 20; i++) {
  6.             Future<Boolean> fi = asyncTask.asyncExec(i, 10L);
  7.             list.add(fi);
  8.         }
  9.         for (int i = 0; i < 20; i++) {
  10.             list.forEach(x -> {
  11.                 try {
  12.                     x.get();
  13.                 } catch (InterruptedException e) {
  14.                     throw new RuntimeException(e);
  15.                 } catch (ExecutionException e) {
  16.                     throw new RuntimeException(e);
  17.                 }
  18.             });
  19.         }
  20.         long time = System.currentTimeMillis() - start;
  21.         return "异步执行,耗时" + time;
  22.     }
复制代码

从上面的运行效果来看,一旦超过8个并行执行的任务,就开始出现等待了。
接下来,我们自定义线程池
  1. @Bean
  2. public TaskExecutor threadPoolTaskExecutor(){
  3.      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  4.      executor.setCorePoolSize(8);
  5.      executor.setMaxPoolSize(16);
  6.      executor.setQueueCapacity(20);
  7.      executor.setKeepAliveSeconds(30);
  8.      executor.setWaitForTasksToCompleteOnShutdown(true);
  9.      executor.setThreadNamePrefix("task-thread-");
  10.      executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
  11.      executor.initialize();
  12.      return executor;
  13. }
复制代码
然后在异步方法的注解中,明确指定所使用的线程池
  1. @Async("threadPoolTaskExecutor")
  2.     public Future<Boolean> asyncExec(int taskId, Long second) {
  3.         exec(taskId, second);
  4.         return new AsyncResult<>(Boolean.TRUE);
  5.     }
复制代码
执行效果如下:


可以看出,线程池设置的参数已经生效。
本人公众号[ 敬YES ]同步更新,欢迎大家关注~




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张国伟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表