美文网首页
定时器(quartz 一)

定时器(quartz 一)

作者: 寂静的春天1988 | 来源:发表于2020-06-18 16:15 被阅读0次

quartz的优缺点

优点:与spring集成、动态添加任务、支持集群
缺点:不支持分布式(只能一个任务在一台服务器上执行,不能分片)

什么是分布式定时任务

将一个任务拆分成多个独立的任务项,由分布式的服务器分别执行某一个或几个分片项。而传统的定时器任务都在一台服务器上执行,如果数据很大那么压力很大。

举例:处理一百万的订单:A服务器处理尾数偶数的订单,B服务器处理尾数奇数的订单。

快速入门

整合java项目
1、引入quartz 依赖
2、quartz.properties

org.quartz.scheduler.instanceName=myScheduler
#配置线程池
org.quartz.threadPool.threadCount=3
#存储到内存中
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

3、

public class Myjob implements Job {

    public void execute(JobExecutionContext context) throws JobExecutionException {
        LocalDateTime time=LocalDateTime.now();
        System.out.println("正在执行"+time +"====>"+Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

public class QuartzDemo {
    public static void main(String[] args) throws Exception {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();
        // 设置任务名称和组名
        JobDetail jobDetail=JobBuilder.newJob(Myjob.class)
                            .withIdentity("jobDetail1","group1")
                            .build();
        //设置每10秒执行一次
        Trigger trigger=TriggerBuilder.newTrigger()
                        .startNow()
                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever())
                        .build();
        
        scheduler.scheduleJob(jobDetail, trigger);
        Thread.sleep(100000);
        //关闭
        scheduler.shutdown();
    }
}

注意:
1、每一个job执行都是一个新的线程(即使是同一个任务,这个elastic-job不同)但是如果在配置文件quartz.properties中配置的线程消耗完,也还是会陷入阻塞的。根据业务来预估线程池的大小。(所以的任务共享一个线程池)
2、每一个job执行都会创建一个新的job对象,所以想通过job的成员变量来传递信息是不可行的(每次都会初始化)
3、myJob类必须要有空的构造方法

JobDataMap传递参数

1、方式1:在创建jobDetail是传递JobDataMap,然后通过JobExecutionContext获取JobDataMap

    public static void main(String[] args) throws Exception {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();
        // 设置任务名称和组名
        JobDetail jobDetail=JobBuilder.newJob(Myjob.class)
                            .withIdentity("jobDetail1","group1")
                            .usingJobData("name", "tom")
                            .build();
        //设置每10秒执行一次
        Trigger trigger=TriggerBuilder.newTrigger()
                        .startNow()
                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
                        .build();
        
        scheduler.scheduleJob(jobDetail, trigger);
        Thread.sleep(100000);
        //关闭
        scheduler.shutdown();
    }

public class Myjob implements Job {

    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap=context.getJobDetail().getJobDataMap();
        String name=jobDataMap.getString("name");
        LocalDateTime time=LocalDateTime.now();
        System.out.println(name+"正在执行"+time +"====>"+Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

2、方式2:在myjob中定义成员变量,并生成get,set方法

public class Myjob implements Job {
    
    private String name;
    
    
    
    
    public String getName() {
        return name;
    }




    public void setName(String name) {
        this.name = name;
    }




    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap=context.getJobDetail().getJobDataMap();
        LocalDateTime time=LocalDateTime.now();
        System.out.println(name+"正在执行"+time +"====>"+Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

如何防止定时器并发

上面我们知道任务间都是并发处理的,那么要考虑并发安全问题。
1、使用@DisallowConcurrentExecution

@DisallowConcurrentExecution
public class Myjob implements Job {
...
}

更新JobDataMap

使用@PersistJobDataAfterExecution注解和jobDataMap.put方法

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class Myjob implements Job {
    
    private int count;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap=context.getJobDetail().getJobDataMap();
        LocalDateTime time=LocalDateTime.now();
        System.out.println(count+"正在执行"+time +"====>"+Thread.currentThread().getName());
        count++;
        jobDataMap.put("count", count);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Trigger

1、startTime属性:设置trigger第一次触发的时间
2、endTime属性:表示trigger的失效时间点
3、优先级(priority)当多个Trigger并发执行,但是线程不够时触发,会优先执行级别高的Trigger

TriggerBuilder.newTrigger().withPriority(10);
默认时5,数字越大优先级越高

4、错过触发(misfire instructions)
1、withMisfireHandlingInstructionDoNothing策略:错过了什么都不做,等待下一次触发时间

设置每5秒执行一次,任务7秒。

public class QuartzDemo {
    public static void main(String[] args) throws Exception {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();
        // 设置任务名称和组名
        JobDetail jobDetail=JobBuilder.newJob(Myjob.class)
                            .withIdentity("jobDetail1","group1")
                            .usingJobData("count", 0)
                            .build();
        //设置每1秒执行一次15:42
        Trigger trigger=TriggerBuilder.newTrigger()
                        .startNow()
                        .withSchedule(
                                CronScheduleBuilder.cronSchedule("*/5 * * * * ?")
                                .withMisfireHandlingInstructionDoNothing()//错过了什么都不做
                        )
                        .build();
        scheduler.scheduleJob(jobDetail, trigger);
    }
}
public class Myjob implements Job {
    
    private int count;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap=context.getJobDetail().getJobDataMap();
        LocalDateTime time=LocalDateTime.now();
        System.out.println(count+"正在执行"+time +"====>"+Thread.currentThread().getName());
        count++;
        jobDataMap.put("count", count);
        try {
            Thread.sleep(7000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

发现这样是不会生效的,因为内部判断了一下错过的时间是否大于misfireThreshold这个值(默认5秒),如果小于还是立即执行。这里我们只失效了2秒,是小于5秒的。

通过quartz.properties设置misfireThreshold的值

org.quartz.scheduler.instanceName=myScheduler
#配置线程池
org.quartz.threadPool.threadCount=1
#存储到内存中
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
#错过的时间
org.quartz.jobStore.misfireThreshold=1000

这样再运行,发现withMisfireHandlingInstructionDoNothing策略生效了。

2、withMisfireHandlingInstructionFireAndProceed策略:错过立即执行

5、日历(calendar)

simple触发器详解

1、可以在具体的时间点执行一次
2、可以按照指定间隔时间重复若干次

cron触发器

1、使用cron表达式触发


image.png

, 代表并且,如果10,20 10秒和20秒都指向

  • 代表范围
  • 代表通配符,每一个可能的值
    / 指定值的增量 比如0/5,从第0秒开始,每隔5秒执行一次,3/5,从第3秒开始每隔5秒执行一次

? 只能出现在日期和星期内,代表没有特定的值。如果使用*号日期了星期会有歧义,这是使用?
L 只能出现在日期和星期内,表示月的最后一天,或者星期六
W 只能出现在日期内,表示最接近这个日期的工作日

使用cron触发器

Trigger trigger=TriggerBuilder.newTrigger()
                        .startNow()
                        .withSchedule(
                                CronScheduleBuilder.cronSchedule("*/5 * * * * ?")
                        )

相关文章

  • Quartz定时器

    Quartz定时器的学习总结_给的再多~不如懂我-CSDN博客_quartz定时器 Quartz定时器 官方文档翻...

  • Spring+Quartz 实现手动开关定时器

    在之前已经讲解了如果配置静态的quartz定时器(传送门:quartz定时器 ),不知道 各位小伙伴有没有成功呢,...

  • springQuartz定时器

    版本springframework:4.2.2.RELEASE;quartz:2.2.2.参见 定时器。 1、依赖...

  • MK-商品上下架方案细化

    设置quartz定时器,每秒遍历数据库(可以考虑时延减轻负担),每秒遍历DB。 首先明确 quartz job工作...

  • Quartz源码阅读

    前言 Quartz是Java实现的定时器框架,该文章分析Quartz执行原理,没有涉及用法。调试中使用到多线程调试...

  • 定时器(quartz 一)

    quartz的优缺点 优点:与spring集成、动态添加任务、支持集群缺点:不支持分布式(只能一个任务在一台服务器...

  • 定时器(Quartz) [kwɔːts]

    Quartz定时器就是对java中Timer定时器的封装,支持Cron表达式定时 使用步骤: 1.定义任务类(指定...

  • Quartz2D绘制时定时器选择

    Quartz2D绘制时定时器要怎么选择呢?我们知道计时器常用有两种: NSTimer定时器 CADisplayLi...

  • Spring中定时器实现

    在一些工作需要使用到定时器,Spring很好的集成了定时器的功能! 在Spring 中使用Quartz,本文介绍S...

  • Azkaban 架构分析

    Azkaban 服务是以 jetty 为服务基础,通过 XML 的方式管理用户,用 Quartz 为定时器,然后通...

网友评论

      本文标题:定时器(quartz 一)

      本文链接:https://www.haomeiwen.com/subject/exibtktx.html