【Java】任务调度的几种方式

最近需要用到任务调度,让我们初步了解一下吧。定时任务的方法包括:

  • 使用Java原生定时任务
  • 使用使用SpringBoot原生任务
  • 使用框架:Quartz /‌Elastic Job‌ / XXL-JOB
框架 核心优势 适用场景 示例依赖
Quartz 支持持久化、集群、复杂Cron规则 企业级分布式调度 quartz 2.3.2
Elastic Job 弹性调度、分片处理、故障转移 大数据量分布式任务 elasticjob-lite-core 3.0.1
XXL-JOB 管理界面、任务路由、失败告警 中小型项目可视化调度 xxl-job-core 2.3.0

Java的原生定时任务

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println("TimerTask执行");
    }
}, 1000, 2000); // 延迟1秒,每2秒执行一次

ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
executor.scheduleAtFixedRate(
    () -> System.out.println("ScheduledExecutor执行"), 
    1, 2, TimeUnit.SECONDS
);
方法 特点
Timer 单线程执行,任务阻塞会导致后续任务延迟
适用于简单场景,无复杂调度需求
ScheduledExecutorService 基于线程池(可配置并发数)
支持任务异常处理,避免单任务失败影响全局

SpringBoot下简单的任务调度Scheduled

https://www.cnblogs.com/luyj00436/p/18710912 。只需要为任务添加@Secheduled,并在启动类中添加@EnableScheduling

Quartz

quartz是开源的任务调度库,它允许开发者通过配置或编程方式定义、调度和管理任务。 quartz的核心功能包含:

  • 任务调度:定义任务的执行计划,并在指定时间或周期性执行任务。
  • 任务管理:管理和控制任务的生命周期,如启动、暂停、删除等。
  • 持久化:支持将任务的状态持久化到数据库,以便在应用重启后恢复任务状态。

核心框架

组件 描述 关键特性 实现方式
Job 定义任务执行逻辑 - 需实现Job接口,重写execute()方法 - 开发者自定义业务逻辑(如数据处理、API调用等) 通过JobBuilder绑定具体实现类(如HelloJob.class
JobDetail 封装Job的元数据 - 包含任务名称、所属组、Job类信息 - 通过反射实例化Job对象 - 支持传递参数(通过JobDataMap 使用JobBuilder.newJob()构建,例如: JobBuilder.newJob(HelloJob.class).build()
Trigger 定义任务触发规则 - 支持SimpleTrigger(固定间隔/单次触发) - 支持CronTrigger(基于Cron表达式) - 可设置优先级和过期时间 通过TriggerBuilder配置,例如: TriggerBuilder.newTrigger().withSchedule(...)
Scheduler 调度器核心容器,协调任务执行 - 注册并管理JobDetailTrigger - 支持集群和持久化 - 提供任务暂停、恢复、删除等操作接口 通过StdSchedulerFactory获取实例,例如: StdSchedulerFactory.getDefaultScheduler()

快速入门

  1. 在Maven项目中引入quartz依赖。

    <dependency>
    	<groupId>org.quartz-scheduler</groupId>
    	<artifactId>quartz</artifactId>
    	<version>2.3.2</version>
    </dependency>
    
  2. 定义job类

    public class HelloQuartz implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("[quartz][当前时间]:" + LocalDateTime.now());
        }
    }
    
  3. 设置任务的配置

    @Configuration
    public class QuartzConfig {
    
        /**
         * 1.定义任务细节
         * @return
         */
        @Bean
        public SchedulerFactory jobDetialFactoryBean() throws SchedulerException {
            // 1. 创建调度器工厂
            SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();
            // 2. 定义任务细节
            org.quartz.JobDetail jobDetail = JobBuilder.newJob(HelloQuartz.class)
                    .withIdentity("MyJob", "group1")
                    .usingJobData("key","value")
                    .build();
            // 3. 定义触发
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("MyTrigger", "group1")
                    .startNow()     // 触发开始时间
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(5)   // 每5s一次
                            .repeatForever())
                    .build();
            // 将任务细节和触发器注册到调度器中
            scheduler.scheduleJob(jobDetail, trigger);
            // 启动调度器
            scheduler.start();
            return schedulerFactory;
        }
    }
    

@Configuration
public class QuartzConfig {
    /**
     * 设置SchedulerFactory 代理工程
     * @return
     */
    @Bean
    public SchedulerFactory getSchedulerFactory() throws SchedulerException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 设置任务 和触发器
        scheduler.scheduleJob(getJobDetail(),getTrigger());
        // 启动
        scheduler.start();
        return schedulerFactory;
    }

    /**
     * 设置一个任务1
     * @return
     * @throws SchedulerException
     */
    private JobDetail getJobDetail() throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(HelloQuartz.class)
                .withIdentity("MyJob","group1")
                .usingJobData("key","value")
                .storeDurably()     // 设置当前任务支持持久化
                .build();
        return jobDetail;
    }

    /**
     * 定义触发器1
     * @return
     * @throws SchedulerException
     */
    private Trigger getTrigger() throws SchedulerException {
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("MyTrigger","group1")
                .startNow()     // 触发器开始时间
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))    // Corn表达式,每5秒执行一次
                .build();
        return trigger;
    }
}

此时,quart能够定时执行任务

XXL-Job 任务使用教程

xxl-Job入门教程:https://www.cnblogs.com/luyj00436/p/18780550

Elastic Job

参考教程,发现Elastic Job强依赖Zooker,在运维复杂度上高于Xxl-Job,社区活跃度上低于Xxl-Job。毕竟高吞吐量,分片式任务的场景并没有那么多。不过,还是简单入门Elastic Job吧。

我也简单的入了个门就走出来了:https://www.cnblogs.com/luyj00436/p/18781122

posted @ 2025-03-19 15:33  陆陆无为而治者  阅读(86)  评论(0)    收藏  举报