Loading

定时任务

1、定时任务

1)cron表达式

语法:

秒 分 时 日 月 周(周几) 年(Spring不支持年,支持前6位)


特殊字符

① , :枚举

7,9,23 * * * * ? 任意时刻的7,9,23秒启动该任务

② - :范围

7-20 * * * * ? 任意时刻的7-20秒,每秒启动一次

③ * :任意 指定位置的任意时刻

④ / :步长

7/5 * * * * ? 任意时刻的第七秒启动,每5秒执行一次

*/5 * * * * ? 任意秒启动,每5秒执行一次

⑤ ?:

(出现在日和周几的位置):为了防止日和周冲突,在周和日上如果要写通配符?

⑥ L:(出现在日和周的位置)

last:最后一个 (cron="* * * ? * 3L"):每月的最后一个周二

⑦ W:

Work Day:工作日 (cron="* * * W * ?"):每个月的工作日触发

(cron="* * * LW * ?"):每个月的最后一个工作日触发

⑧ #:第几个

(cron="* * * ? * 5#2"):每个月的第 2 个周 4


2)SpringBoot整合corn表达式做定时任务

/*
 * 定时任务
 * 1、@EnableScheduling 开启定时任务功能
 * 2、@Scheduled 开启定时任务
 * 3、自动配置类: TaskSchedulingAutoConfiguration
 *
 * 异步任务
 *   1、@EnableAsync: 开启异步任务
 *   2、在方法上标注 @Async
 *   3、自动配置类: TaskExecutionAutoConfiguration
 *         属性默认绑定: TaskExecutionProperties
 */
@Slf4j
@EnableAsync
@EnableScheduling
@Component
public class HelloSchedule {

    /*
    * 1、cron表达式不支持第7位的年
    * 2、周: 1-7 代表周一到周日
    * 3、定时任务不应该阻塞。默认是阻塞的
    *       1)让业务以异步的方式自己提交到线程池
    *       CompletableFuture.runAsync(()->{
    *            xxxxService.hello();
    *        }, executor);

            2)支持定时任务线程池
            设置 TaskSchedulingProperties(定时任务配置绑定类)
            spring.task.scheduling.pool.size: xxx  => 有些版本不一定好使


            3)直接让定时任务异步执行
            @EnableAsync + @Async

            使用异步 + 定时任务来完成定时任务不阻塞的功能


    * */
    @Scheduled(cron = "* * * * * ?")
    public void hello() throws InterruptedException {
        log.info("hello。。。");
        Thread.sleep(3000);
    }
}


3)、定时任务-分布式系统下的问题

当同个服务启动多个时:

①、需要使用分布式锁,来保证只有一个服务来执行定时任务。

②、同时需要保证定时任务执行的幂等性

image-20220326092719153


@Service
public class SeckillSkuScheduled {

    @Autowired
    SeckillService seckillService;

    @Autowired
    RedissonClient redissonClient;

    private final String upload_lock = "seckill:upload:lock";

    //todo 幂等性问题 -> 同一件秒杀商品不应该上架两次
    @Scheduled(cron = "0 * * * * ?")
    public void uploadSeckillSkuLatest3Days(){
        //重复上架无需处理
        System.out.println("秒杀商品上架...");
        //加上分布式锁,保证只有一个定时任务执行
        RLock lock = redissonClient.getLock(upload_lock);
        lock.lock(10, TimeUnit.SECONDS); //十秒中没有执行完,自动释放锁,不会造成死锁
        try {
            seckillService.uploadSeckillSkuLatest3Days();
        } finally {
            lock.unlock();
        }
    }
}
posted @ 2022-03-28 12:52  青岑  阅读(209)  评论(1编辑  收藏  举报