张国伟 发表于 2023-9-1 11:58:06

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

本节我们一起学习一下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
https://img2023.cnblogs.com/blog/37001/202308/37001-20230822162534731-235767734.png
http://localhost:16001/async/async_task
https://img2023.cnblogs.com/blog/37001/202308/37001-20230822162604609-1033011007.png
注意:异步方法和调用一定要写在不同的类中
二、线程池配置

上面的例子,在耗时服务多的情况下,使用异步方法确实提高了响应速度。但是它默认启用的是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;
    }https://img2023.cnblogs.com/blog/37001/202308/37001-20230822164547506-615559233.png
从上面的运行效果来看,一旦超过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);
    }执行效果如下:
https://img2023.cnblogs.com/blog/37001/202308/37001-20230822173944316-1626972881.png
https://img2023.cnblogs.com/blog/37001/202308/37001-20230823093142199-36114177.png
可以看出,线程池设置的参数已经生效。
本人公众号[ 敬YES ]同步更新,欢迎大家关注~


https://img2023.cnblogs.com/blog/37001/202308/37001-20230822194405666-261743903.jpg

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 原来你是这样的SpringBoot--Async异步任务