首页 > 其他分享 >聊一聊非分布式任务调度@Scheduled

聊一聊非分布式任务调度@Scheduled

时间:2023-07-01 11:33:21浏览次数:40  
标签:Scheduled 10 任务调度 Java 30 任务 聊一聊 15 执行


@Scheduled注解是Spring Boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行,默认是在单线程中执行的

1、注解源码

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
@Reflective
public @interface Scheduled {
    String CRON_DISABLED = "-";

    String cron() default "";

    String zone() default "";

    long fixedDelay() default -1L;

    String fixedDelayString() default "";

    long fixedRate() default -1L;

    String fixedRateString() default "";

    long initialDelay() default -1L;

    String initialDelayString() default "";

    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

2、参数说明

参数

说明

示例

cron

任务执行的cron表达式

0/1 * * * * ?

zone

cron表达时解析使用的时区,默认为服务器的本地时区,使用java.util.TimeZone#getTimeZone(String)方法解析

GMT-8:00

fixedDelay

上一次任务执行结束到下一次执行开始的间隔时间,单位为ms

2000

fixedDelayString

上一次任务执行结束到下一次执行开始的间隔时间,使用java.time.Duration#parse解析

PT15M

fixedRate

以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务

2000

fixedRateString

与fixedRate逻辑一致,只是使用java.time.Duration#parse解析

PT15M

initialDelay

首次任务执行的延迟时间

2000

initialDelayString

首次任务执行的延迟时间,使用java.time.Duration#parse解析

PT15M

timeUnit

3、详解说明

1、cron 参数

表达式格式:@Scheduled(cron = "{秒数} {分钟} {小时} {日期} {月份} {星期}")

注意: cron表达式可分为6或7个占位符,但在spring自带的定时任务中,cron只支持6个参数,若使用7个参数就会报错

Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'test': Cron expression must consist of 6 fields (found 7 in "*/5 * * * * * *")

代码示例:

/**
 * cron 表达式 每隔5秒执行一次
 */
@Scheduled(cron = "*/5 * * * * *")
public void test(){
    log.info("小熊学Java是最全Java学习网站!");
}

结果

2023-06-28T15:20:40.009+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:45.014+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:50.004+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:55.010+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:21:00.002+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!

更多的cron表达式,自行测试哈,这里不做过多演示

“30 * * * * ?” 每半分钟触发任务 
 
“30 10 * * * ?” 每小时的10分30秒触发任务 
 
“30 10 1 * * ?” 每天1点10分30秒触发任务 
 
“30 10 1 20 * ?” 每月20号1点10分30秒触发任务 
 
“30 10 1 20 10 ? *” 每年10月20号1点10分30秒触发任务 
 
“30 10 1 20 10 ? 2011” 2011年10月20号1点10分30秒触发任务 
 
“30 10 1 ? 10 * 2011” 2011年10月每天1点10分30秒触发任务 
 
“30 10 1 ? 10 SUN 2011” 2011年10月每周日1点10分30秒触发任务 
 
“15,30,45 * * * * ?” 每15秒,30秒,45秒时触发任务 
 
“15-45 * * * * ?” 15到45秒内,每秒都触发任务 
 
“15/5 * * * * ?” 每分钟的每15秒开始触发,每隔5秒触发一次 
 
“15-30/5 * * * * ?” 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次 
 
“0 0/3 * * * ?” 每小时的第0分0秒开始,每三分钟触发一次 
 
“0 15 10 ? * MON-FRI” 星期一到星期五的10点15分0秒触发任务 
 
“0 15 10 L * ?” 每个月最后一天的10点15分0秒触发任务 
 
“0 15 10 LW * ?” 每个月最后一个工作日的10点15分0秒触发任务 
 
“0 15 10 ? * 5L” 每个月最后一个星期四的10点15分0秒触发任务 
 
“0 15 10 ? * 5#3” 每个月第三周的星期四的10点15分0秒触发任务

2、fixedDelay 参数

fixedDelay 上一次任务执行结束到下一次执行开始的间隔时间,单位为ms

代码示例:

/**
 * fixedDelay 上一次任务执行结束到下一次执行开始的间隔时间,单位为ms
 * 每隔2秒执行一次
 */
@Scheduled(fixedDelay = 2000)
public void testFixedDelay (){
    log.info("小熊学Java是最全Java学习网站!");
}

结果展示:

聊一聊非分布式任务调度@Scheduled_线程池

3、fixedRate参数

以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务

/**
     * 以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若
     * 在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务
     * 每隔2秒执行一次
     */
    @Scheduled(fixedRate = 2000)
    public void testFixedRate () throws InterruptedException {
        Thread.sleep(3000);
        log.info("小熊学Java是最全Java学习网站!");
    }

日志每3秒执行一次,这也是因为@Scheduled是在单线程中执行的

聊一聊非分布式任务调度@Scheduled_Java_02

4、initialDelay参数

首次任务执行的延迟时间

/**
     * initialDelay  首次任务执行的延迟时间
     * 每隔2秒执行一次
     */
    @Scheduled(fixedRate = 2000, initialDelay = 3000)
    public void testInitialDelay (){
        log.info("小熊学Java是最全Java学习网站!");
    }

首次延迟的时间是3秒,之后每2秒执行一次

聊一聊非分布式任务调度@Scheduled_分布式_03

4、@Scheduled多线程

1、场景演示

执行以下两个方法

@Scheduled(fixedRate = 2000)
public void test1 () throws InterruptedException {

    Thread.sleep(3000);
    log.info("小熊学Java 是最全Java学习网站!---test1");
}
@Scheduled(fixedRate = 2000)
public void test2 () throws InterruptedException {
    Thread.sleep(3000);
    log.info("小熊学Java是最全Java学习网站!---test2");
}

聊一聊非分布式任务调度@Scheduled_线程池_04

从执行结果中可以看出,test1方法和test2方法交替输出日志,并没有同时执行

org.springframework.scheduling.config.ScheduledTaskRegistrar源码发现

protected void scheduleTasks() {
    //如果为空,则以单线程执行
    if (this.taskScheduler == null) {
        this.localExecutor = Executors.newSingleThreadScheduledExecutor();
        this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
    }

    Iterator var1;
    if (this.triggerTasks != null) {
        var1 = this.triggerTasks.iterator();

        while(var1.hasNext()) {
            TriggerTask task = (TriggerTask)var1.next();
            this.addScheduledTask(this.scheduleTriggerTask(task));
        }
    }

    if (this.cronTasks != null) {
        var1 = this.cronTasks.iterator();

        while(var1.hasNext()) {
            CronTask task = (CronTask)var1.next();
            this.addScheduledTask(this.scheduleCronTask(task));
        }
    }

    IntervalTask task;
    if (this.fixedRateTasks != null) {
        var1 = this.fixedRateTasks.iterator();

        while(var1.hasNext()) {
            task = (IntervalTask)var1.next();
            if (task instanceof FixedRateTask) {
                FixedRateTask fixedRateTask = (FixedRateTask)task;
                this.addScheduledTask(this.scheduleFixedRateTask(fixedRateTask));
            } else {
                this.addScheduledTask(this.scheduleFixedRateTask(new FixedRateTask(task)));
            }
        }
    }

    if (this.fixedDelayTasks != null) {
        var1 = this.fixedDelayTasks.iterator();

        while(var1.hasNext()) {
            task = (IntervalTask)var1.next();
            if (task instanceof FixedDelayTask) {
                FixedDelayTask fixedDelayTask = (FixedDelayTask)task;
                this.addScheduledTask(this.scheduleFixedDelayTask(fixedDelayTask));
            } else {
                this.addScheduledTask(this.scheduleFixedDelayTask(new FixedDelayTask(task)));
            }
        }
    }

}

当未手动指定taskScheduler时,会通过Executors.newSingleThreadScheduledExecutor()创建默认的单线程线程池,且该线程池的拒绝策略为AbortPolicy,这种策略在线程池无可用线程时丢弃任务,并抛出异常RejectedExecutionException

2、多线程配置

1、配置bean

在启动类中,配置bean,代码如下:

/**
 * 配置线程池
 * @return
 */
@Bean
public TaskScheduler config(){
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    //线程池大小为10
    taskScheduler.setPoolSize(10);
    return taskScheduler;
}

聊一聊非分布式任务调度@Scheduled_分布式_05

2、配置类

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //Scheduler指定线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}

运行结果跟上面一样,每3秒同时执行

5、Async异步执行

异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。

1、简单使用

Spring Boot的异步任务,只需在方法上添加异步注解,同时开启异步任务

@Component
@Slf4j
public class AsyncTask {

    @Async
    public void test(){
        log.info("小熊学Java 是最棒的!!!");
    }
}

方法调用

@Resource
    private AsyncTask asyncTask;

    @Scheduled(fixedRate = 2000)
    public void test1 () throws InterruptedException {
        asyncTask.test();
        Thread.sleep(3000);
        log.info("小熊学Java 是最全Java学习网站!---test1");
    }

结果输出

聊一聊非分布式任务调度@Scheduled_java_06

2、异步失效

1、异步方法和调用异步方法在同一个类中

有时候,经常看到编写异步任务,都是这样写的

@Scheduled(fixedRate = 2000)
public void test1 () throws InterruptedException {
    asyncTask.test();
    Thread.sleep(3000);
    log.info("小熊学Java 是最全Java学习网站!---test1");
}

@Async
public void test(){
    log.info("小熊学Java 是最棒的!!!");
}

这样写是不会生效的,由于@Async的AdviceMode默认为PROXY,所以当调用方和被调用方是在同一个类中,无法产生切面,@Async没有被Spring容器管理,可以查看源码,

好了,本文就到这里了!如果觉得内容不错的话,希望大家可以帮忙点赞转发一波,这是对我最大的鼓励,感谢

标签:Scheduled,10,任务调度,Java,30,任务,聊一聊,15,执行
From: https://blog.51cto.com/xiaobear/6598604

相关文章

  • 聊一聊这些年用过的绘图工具
    码农从只需要敲代码到需要绘图,而且是负责所在团队的相关图表绘制时,就是TA的岗位与角色发生变化,准确地说是得到提升的时刻。诸如“不会画图的程序员,不是好的技术扛把子”之类调侃,也是绘图能力对于开发人员以及团队的重要性的一种诙谐表达。今天,就来聊聊这些年来所用过的绘图工具。期......
  • Linux-篇五:定时任务调度
    定时任务调度crond任务调度介绍crontab进行定时任务的设置快速入门特殊时间执行案例应用案例crond相关指令crontab-r:终止任务调度crontab-l:查看任务调度servicecrondrestart:重启任务调度at定时任务基本介绍命令格式at命令选项at时间定义应用案例......
  • 聊一聊 Lua 的基础数据类型:数值、布尔、字符串
    楔子任何一门语言都提供了不同类型的数据结构,那么Lua中都有哪些数据结构呢?nil:空boolean:布尔类型,分别是true和falsenumber:数值类型,整型和浮点型都属于numberstring:字符串table:表function:函数userdata:用户数据thread:线程Lua总共提供了以上8种数据类型,目前只需要......
  • C++面试八股文:聊一聊指针?
    C++面试八股文:聊一聊指针?某日二师兄参加XXX科技公司的C++工程师开发岗位第17面:面试官:聊一聊指针?二师兄:好的。面试官:你觉得指针本质上是什么?二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假设它的地址是从0x00000000到0x3fffffff,每一个字节都对应一个地......
  • 聊一聊 Rust 的 stack overflow
    早上看到了这篇文章智能指针有可能会让你的应用崩溃,下面分析一下会导致stackoverflow的代码structNode<T>{val:T,next:Option<Box<Node<T>>>,}structLinkedList<T>{head:Option<Box<Node<T>>>,}impl<T>LinkedList<T&......
  • 聊一聊多源最短路径问题(只有5行代码哦)
    暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程。上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。我们现在需要求任意两个城市之......
  • 开源的轻量级任务调度框架
    你好,这里是Dotnet工具箱,定期分享Dotnet有趣,实用的工具和组件,希望对您有用!1.开源的轻量级任务调度框架FluentScheduler是一个开源的任务调度框架,支持Fluent语法,通过Nuget安装引用,和Quartz.Net相比,FluentScheduler足够轻量,非常容易上手。使用示例下面是一个仅仅......
  • 如何设计一个海量任务调度系统
    背景在日常开发中会经常遇到一些需要异步定时执行的业务诉求,典型的使用场景如:超时未支付订单关单、每隔2h更新好友排行榜、3.22日17点《xx》剧上线等。目前业务侧多基于以下思路来快速搭建一个调度系统,mysql或者redis队列存储待执行任务,通过crontab定时触发应用完成“......
  • C++面试八股文:聊一聊指针?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第17面:面试官:聊一聊指针?二师兄:好的。面试官:你觉得指针本质上是什么?二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假设它的地址是从0x00000000到0x3fffffff,每一个字节都对应一个地址。当我们声明一个变量并初始化它......
  • C++面试八股文:聊一聊指针?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第17面:面试官:聊一聊指针?二师兄:好的。面试官:你觉得指针本质上是什么?二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假设它的地址是从0x00000000到0x3fffffff,每一个字节都对应一个地址。当我们声明一个变量并初始化......