SpringBoot中的异步任务

@Async

编写两个异步任务,方法上使用@Async注解,同时启动类或异步任务类上开启@EnableAsync注解

需要注意

  1. 要把异步任务封装在类里面,不能直接写在Controller类中
@Slf4j
@Component
public class TaskService {

    @Async
    public void task1(){
        try {
            Thread.sleep(1000);
            log.info("执行了异步task1");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async
    public void task2(){
        try {
            Thread.sleep(1000);
            log.info("执行了异步task1");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@Slf4j
@RestController
public class AsyncController {

    @Autowired
    private TaskService taskService;

    @RequestMapping("/asyncTask")
    public String AsyncTask() throws ExecutionException, InterruptedException {
        log.info("开始执行异步任务");
        taskService.task1();

        taskService.task2();

        log.info("AsyncTask方法执行完毕");
        return "hello";

    }
}

-----------------------
从控制台结果可以看到主线程先输出了“AsyncTask方法执行完毕”,后输出两个异步线程的运行结果,证明异步线程任务开启成功
2023-03-17 11:55:52.752  INFO 9800 --- [nio-8001-exec-2] c.l.test.controller.AsyncController      : 开始执行异步任务
2023-03-17 11:55:52.754  INFO 9800 --- [nio-8001-exec-2] c.l.test.controller.AsyncController      : AsyncTask方法执行完毕
2023-03-17 11:55:53.776  INFO 9800 --- [         task-1] com.ligong.test.service.TaskService      : 执行了异步task1
2023-03-17 11:55:54.771  INFO 9800 --- [         task-2] com.ligong.test.service.TaskService      : 执行了异步task2
带有返回值的异步任务
  1. 带有返回值的异步任务用Future作为方法返回值
  2. 用AsyncResult对象返回输出结果
@Async
public Future<Long> task2(){

    long startTime = System.currentTimeMillis();

    try {
        Thread.sleep(2000);
        log.info("执行了异步task2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long endTime = System.currentTimeMillis();
	
    //返回task2异步线程的执行时间
    return new AsyncResult<>(endTime-startTime);

}
@RequestMapping("/asyncTask")
public String AsyncTask() throws ExecutionException, InterruptedException {
    log.info("开始执行异步任务");
    taskService.task1();

    //异步任务2有返回值
    Future<Long> task2Time = taskService.task2();
    Long time = task2Time.get();
    log.info("异步线程task2执行花费时间为"+time+"毫秒");

    log.info("AsyncTask方法执行完毕");
    return "hello";

}

-------------------------------------
可以看到主线程需要同步等待task2异步线程的输出结果,才能继续向下执行
    
2023-03-17 14:31:36.468  INFO 20692 --- [nio-8001-exec-1] c.l.test.controller.AsyncController      : 开始执行异步任务
2023-03-17 14:31:37.479  INFO 20692 --- [         hello1] com.ligong.test.service.TaskService      : 执行了异步task1
2023-03-17 14:31:38.485  INFO 20692 --- [         hello2] com.ligong.test.service.TaskService      : 执行了异步task2
2023-03-17 14:31:38.486  INFO 20692 --- [nio-8001-exec-1] c.l.test.controller.AsyncController      : 异步线程task2执行花费时间为2007毫秒
2023-03-17 14:31:38.486  INFO 20692 --- [nio-8001-exec-1] c.l.test.controller.AsyncController      : AsyncTask方法执行完毕

源码:

使用@Async注解开启的异步任务,是Spring自定义线程池实现的

通过源码可以看到,Spring默认的线程池核心线程数为8,最大线程数为Integer.MAX_VALUE,阻塞队列为Integer.MAX_VALUE,可能造成无限的非核心线程的创建,这是一种资源浪费

public static class Pool {

   /**
    * Queue capacity. An unbounded capacity does not increase the pool and therefore
    * ignores the "max-size" property.
    */
   private int queueCapacity = Integer.MAX_VALUE;

   /**
    * Core number of threads.
    */
   private int coreSize = 8;

   /**
    * Maximum allowed number of threads. If tasks are filling up the queue, the pool
    * can expand up to that size to accommodate the load. Ignored if the queue is
    * unbounded.
    */
   private int maxSize = Integer.MAX_VALUE;

   /**
    * Whether core threads are allowed to time out. This enables dynamic growing and
    * shrinking of the pool.
    */
   private boolean allowCoreThreadTimeout = true;

   /**
    * Time limit for which threads may remain idle before being terminated.
    */
   private Duration keepAlive = Duration.ofSeconds(60);
}

根据Spring自动装配原理,修改Spring默认提供的线程池参数

spring:
  task:
    execution:
      pool:
        core-size: 5
        max-size: 50
        queue-capacity: 200 #阻塞队列最大值为200
      thread-name-prefix: hello  #线程前缀
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值