一、什么是 Cron 表达式

Cron 表达式是一种用于配置定时任务执行时间的字符串格式,由 6~7 个字段组成,定义了任务在何时执行。

在 Java 中,Cron 表达式广泛应用于:

  • Spring Task (@Scheduled)
  • Quartz Scheduler
  • xxl-jobElastic-Job 等分布式调度框架

二、Cron 表达式结构

标准 6 字段格式(Spring/Quartz 通用)

┌───────────── 秒 (0-59)
│ ┌───────────── 分 (0-59)
│ │ ┌───────────── 时 (0-23)
│ │ │ ┌───────────── 日 (1-31)
│ │ │ │ ┌───────────── 月 (1-12 或 JAN-DEC)
│ │ │ │ │ ┌───────────── 周 (0-7 或 SUN-SAT, 0/7=周日)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *

7 字段格式(部分框架支持,含年字段)

* * * * * * *
│ │ │ │ │ │ │
│ │ │ │ │ │ └─ 年 (可选, 1970-2099)
│ │ │ │ │ └─── 周
│ │ │ │ └───── 月
│ │ │ └─────── 日
│ │ └───────── 时
│ └─────────── 分
└───────────── 秒

三、字段取值与特殊字符

字段

允许值

特殊字符

0-59

, - * /

0-59

, - * /

0-23

, - * /

1-31

, - * / ? L W

1-12 / JAN-DEC

, - * /

0-7 / SUN-SAT

, - * / ? L #

1970-2099

, - * /

特殊字符详解

字符

含义

示例

*

任意值,每...

* * * * * * 每秒执行

?

不指定(日和周互斥)

0 0 1 * * ? 每月1日执行,不指定周

-

范围

10-20 10到20

,

列表

1,3,5 1、3、5

/

步长/间隔

0/5 从0开始每5个单位

L

最后(Last)

L 月末最后一天,6L 最后一个周五

W

工作日(Weekday)

15W 最接近15日的工作日

#

第几个周几

2#3 第3个周一


四、常用 Cron 表达式示例

基础周期任务

表达式

说明

0/1 * * * * ?

每秒执行

0 * * * * ?

每1分钟执行(整分触发)

0 0/5 * * * ?

每5分钟执行

0 0 * * * ?

每小时执行(整点)

0 0 0/2 * * ?

每2小时执行

0 0 0 * * ?

每天0点执行

0 0 12 * * ?

每天中午12点执行

特定时间点

表达式

说明

0 30 8 ? * MON-FRI

工作日8:30执行

0 0 9,18 * * ?

每天9点和18点执行

0 0 10 L * ?

每月最后一天10点执行

0 0 10 1 * ?

每月1号10点执行

0 0 10 ? * 2#1

每月第1个周一10点执行

0 0 10 15 * ?

每月15号10点执行

0 0 10 15W * ?

每月15日最近工作日10点执行

复杂场景

表达式

说明

0 0 0 1 1 ? *

每年1月1日0点执行

0 0 0 1 1/3 ?

每季度首月1日执行(1,4,7,10月)

0 0 0 ? * 6L

每月最后一个周五0点执行

0 0 0 LW * ?

每月最后一个工作日0点执行


五、Spring Boot 实战

1. 启用定时任务

@SpringBootApplication
@EnableScheduling  // 开启定时任务
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 创建定时任务

@Component
@Slf4j
public class ScheduledTasks {

    /**
     * 每5秒执行一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void taskEvery5Seconds() {
        log.info("每5秒执行,当前时间:{}", LocalDateTime.now());
    }

    /**
     * 每天凌晨1点执行数据清理
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void dailyCleanup() {
        log.info("开始每日数据清理...");
        // 执行清理逻辑
    }

    /**
     * 工作日早8点半发送日报
     */
    @Scheduled(cron = "0 30 8 ? * MON-FRI")
    public void sendDailyReport() {
        log.info("发送工作日报...");
    }

    /**
     * 每月1号0点生成月报
     */
    @Scheduled(cron = "0 0 0 1 * ?")
    public void generateMonthlyReport() {
        log.info("生成月度报表...");
    }
}

3. 动态配置 Cron 表达式

@Component
@Slf4j
public class DynamicScheduledTask implements SchedulingConfigurer {

    @Autowired
    private TaskConfigRepository configRepository; // 从数据库读取配置

    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {
        registrar.addTriggerTask(
            this::executeTask,
            triggerContext -> {
                // 从数据库获取最新cron表达式
                String cron = configRepository.findCronByTaskName("dataSync");
                if (StringUtils.isEmpty(cron)) {
                    cron = "0 0/30 * * * ?"; // 默认每30分钟
                }
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        );
    }

    public void executeTask() {
        log.info("执行动态配置的任务,时间:{}", LocalDateTime.now());
    }
}

4. 异步定时任务(防止阻塞)

@Configuration
@EnableAsync  // 开启异步
@EnableScheduling
public class AsyncConfig {
    
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("task-");
        executor.initialize();
        return executor;
    }
}

@Component
public class AsyncScheduledTasks {

    @Async("taskExecutor")
    @Scheduled(cron = "0 0/1 * * * ?")
    public void asyncTask() {
        // 长时间任务不会阻塞其他定时任务
        log.info("异步任务开始...");
        Thread.sleep(10000); // 模拟耗时操作
        log.info("异步任务结束...");
    }
}

六、Quartz 框架使用

Maven 依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

定义 Job

public class DataSyncJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap data = context.getJobDetail().getJobDataMap();
        String param = data.getString("param");
        System.out.println("Quartz Job 执行,参数:" + param + 
                          ",时间:" + new Date());
    }
}

调度配置

public class QuartzDemo {
    public static void main(String[] args) throws Exception {
        // 1. 创建调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();

        // 2. 创建 JobDetail
        JobDetail job = JobBuilder.newJob(DataSyncJob.class)
                .withIdentity("dataSyncJob", "group1")
                .usingJobData("param", "user_data")
                .build();

        // 3. 创建 Trigger(Cron 表达式)
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("dataSyncTrigger", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
                .build();

        // 4. 调度执行
        scheduler.scheduleJob(job, trigger);
        
        // 保持运行
        Thread.sleep(100000);
        scheduler.shutdown();
    }
}

七、常见问题与注意事项

⚠️ 重要提醒

  • 日和周字段互斥:不能同时指定具体值,必须有一个为 ?
    •  ❌ 0 0 1 1 * 1(错误:同时指定了日和周)
    •  ✅ 0 0 1 1 * ?(正确:指定日,周用?)
  • Quartz vs Spring 差异
    • Spring 默认6字段(无年)
    • Quartz 支持7字段(含年)
  • 时区问题
    • @Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Shanghai")
  • 任务重叠:默认单线程,长任务会阻塞后续执行,建议使用 @Async 或线程池
  • 集群环境:单机 @Scheduled 会多节点重复执行,需用分布式锁或 Quartz 集群模式

八、快速参考卡片

常用表达式速查:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
每秒          0/1 * * * * ?
每5秒         0/5 * * * * ?
每分钟        0 * * * * ?
每5分钟       0 0/5 * * * ?
每小时        0 0 * * * ?
每2小时       0 0 0/2 * * ?
每天0点       0 0 0 * * ?
每天8点       0 0 8 * * ?
工作日8:30    0 30 8 ? * MON-FRI
每月1日0点    0 0 0 1 * ?
每月最后1天   0 0 0 L * ?
每周日0点     0 0 0 ? * 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐