SpringBoot整合定时任务和异步任务

590 阅读2分钟

定时任务schedule

什么是定时任务

  • 某个时间定时处理某个任务
  • 发邮件、短信等
  • 消息提醒
  • 订单通知
  • 统计报表系统

常见的定时任务

  • Java⾃带的java.util.Timer类配置⽐较麻烦,有时间延后问题
  • Quartz框架: 配置更简单,xml或者注解适合分布式或者⼤型调度作业
  • SpringBoot框架⾃带

springboot使用注解方式开启定时任务的例子

  1. 启动类⾥⾯ @EnableScheduling开启定时任务,⾃动扫描
  2. 定时任务业务类 加注解 @Component被容器扫描
  3. 定时执⾏的⽅法加上注解 @Scheduled(fixedRate=2000) 定期执⾏⼀次

简单实现

@Component
class TimeTask {
    @Scheduled(fixedRate = 2500)
    public void sum(){
        System.out.println("当前时间"+new Date());
    }
}

启动项目,看到每2秒打印一次信息

image.png

cron 定时任务表达式 @Scheduled(cron="*/1 * * * * *") 表示每秒,crontab ⼯具 tool.lu/crontab/ fixedRate: 定时多久执⾏⼀次(上⼀次开始执⾏时间点后xx秒再次执⾏;) fixedDelay: 上⼀次执⾏结束时间点后xx秒再次执⾏

使用fixedDelay

@Component
class TimeTask {
    @Scheduled(fixedDelay = 2500)
    public void sum(){
        try {
            System.out.println("当前时间"+new Date());
            Thread.sleep(2500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

image.png

可以看到变成5秒执行一次

异步任务

什么是异步任务

想吃泡面了,在烧水的时候,同时能把泡面包装拆掉。即多个任务同时进行 适⽤于处理log、发送邮件、短信……等

  • 下单接⼝->查库存 1000
  • 余额校验 1500
  • ⻛控⽤户1000
启动类⾥⾯使⽤@EnableAsync注解开启功能,⾃动扫描
定义异步任务类并使⽤@Component标记组件被容器扫描,异步⽅法加上@Async

简单演示

编写异步方法,启动类⾥⾯使⽤@EnableAsync注解开启功能

@Component
@Async
public class AsyncTask {
    public void task1(){
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task 1");
    }
    public void task2(){
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task 2");
    }
    public void task3(){
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task 3");
    }
}

在controller调用

    @RequestMapping("async")
    public JsonData testAsync(){
        long start = System.currentTimeMillis();
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
        return JsonData.buildSuccess(end-start);
    }

可以看到方法的打印是随机的并且同时完成,而非等待4s轮流调用

image.png
image.png

异步任务Future获取结果

定义异步任务类获取结果

要把异步任务封装到类⾥⾯,不能直接写到Controller 增加Future 返回结果 AsyncResult("task执⾏完成"); 如果需要拿到结果 需要判断全部的 task.isDone()

在之前的异步代码中添加

    public Future<String> task4(){
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new AsyncResult<String>("task4");
    }
    public Future<String> task5(){
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new AsyncResult<String>("task5");
    }

然后进行判断调用

@RequestMapping("future")
    public JsonData testAsyncFuture(){
        long start = System.currentTimeMillis();

        Future<String> task4 = asyncTask.task4();
        Future<String> task5 = asyncTask.task5();
        System.out.println(task4+">>>and<<<"+task5);

        while (true){
            if (task4.isDone() && task5.isDone()){
                try {
                    String s = task4.get()+"<<<>>>"+task5.get();
                    System.out.println(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }finally {
                    break;
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
        return JsonData.buildSuccess(end-start);
    }

image.png