SpringBoot2.X整合定时任务和异步任务

什么是定时任务,使用场景:

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

常见定时任务

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

SpringBoot使用注解方式开启定时任务:

  • 启动类里面 @EnableScheduling开启定时任务,自动扫描
  • 定时任务业务类 加注解 @Component被容器扫描
  • 定时执行的方法加上注解 @Scheduled(fixedRate=2000) 定期执行一次
  • 补充题外: @PostConstruct 只执行一次(是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。)
  • 定时任务默认是单线程的

Scheduled 参数设置:

  • cron 定时任务表达式 @Scheduled(cron="*/1 * * * * *") 表示每秒 (上一个任务未完成 下一个任务排队)

  • fixedRate: 定时多久执行一次(上一次开始执行时间点后xx秒再次执行)

    • (fixedRate有个坑,单线程的时候当任务执行时长超过设置的间隔时长时 后续任务会被阻塞 只有前一个任务执行完成后 后续任务就会立马执行 举个例子:(假如设置的fixedRate=3*1000,理论上 但是当第一个任务开始时 第三秒后就会调用第二次任务 但是第一个任务开始到结束用了7秒 ,所以开始第一个任务到结束 中途重新调用了两次任务 但第二个任务 和 第三个任务都被阻塞了 第二个和第三个任务就在排队 当第一个任务结束后 第二个任务就睡立马执行))
    • 解决@Scheduled(fixedRate)如何避免任务被阻塞

      • 加上注解@EnableAsync(类上)和@Async(方法上),加了注解以后,就开启了多线程模式,当到了下一次任务的执行时机时,如果上一次任务还没执行完,就会自动创建一个新的线程来执行它。异步执行也可以理解为保证了任务以固定速度执行。

  • fixedDelay: 上一次执行结束时间点后xx秒再次执行

例子:


@Component
public class RecruitContract {

    @Scheduled(cron="*/1 * * * * *") 
    public void explainLogs(){
        System.out.println("每1秒执行一次");
    }

    //@Async 异步   启动类需要加 @EnableAsync (开启异步)
    @Scheduled(fixedRate = 3 * 1000)
    public void explainLogs(){
        System.out.println("上一个任务开始后 3秒执行");
    }
    @Scheduled(fixedDelay= 3 * 1000)
    public void explainLogs(){
        System.out.println("上一个任务结束三秒后 3秒执行 ");
    }
    @PostConstruct
    public void explainLogs(){
        System.out.println("项目启动执行一次");
    }

}


@SpringBootApplication
//@EnableAsync  (开启异步)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

SpringBoot异步任务EnableAsync:

JUC-04 中的异步回调有补充
  • 什么是异步任务

    • 异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。

  • 使用场景:适用于处理log、发送邮件、短信……等()

    • 下单接口->查库存 1000
    • 余额校验 1500
    • 风控用户1000
  • 启动类里面使用@EnableAsync注解开启功能,自动扫描

  • 定义异步任务类并使用@Component标记组件被容器扫描,异步方法加上@Async(也可以加在类上 代表该类所有方法都是异步方法)  

实例:

@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 ");
    }

}

//在同一个类的同一个方法里调用 
    task1();
    task2();

运行时间 大概在4S

使用SpringBoot开发异步任务Future获取结果:

  • 注意点:

    • 要把异步任务封装到类里面,不能直接写到Controller
    • 增加Future 返回结果 AsyncResult("task执行完成");
    • 如果需要拿到结果 需要判断全部的 task.isDone()
@Component
@async
public class AsyncTask {
    public Future<String> task4() {
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(" task 4 ");
        return new AsyncResult<String>( "task5");
    }
    public Future<String> task5() {
        try {
            Thread.sleep(4000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(" task 5 ");
        return new AsyncResult<String>( "task5");
    }

}


同一个类里同一个方法调用

 Future<String> task4 =asyncTask.task4();
    Future<String> task5 =asyncTask.task5();
    for(;;){
         //判断所有异步方法是否执行完毕
         if(task4.isDone() && task5.isDone()){  
             try{
                String task4Result = task4.get();
                System.out.printin(task4Result):
                String task5Result = task5.get();
                System.out.println(task5Result);
            } catch (InterruptedException e){
                    e.printStackTrace();
            } catch (ExecutionException e){
                    e.printStackTrace();
            }finally {
                    break;
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值