定时器quartz的简单使用

定时器quartz

顾名思义,定时去执行某工作。就比如给扫地机器人定时去扫地,定时需要人去调度(调度器),人需要去设定扫地的执行的时间即什么时候开始,什么时候结束(触发器),并指定扫地机器人去打扫哪块,即详细的工作(任务)。

部署到服务器请参考:https://blog.csdn.net/Andrew_Yuan/article/details/89015548

1.定时器的几个关键概念:
触发器 Trigger: 什么时候工作
任务 Job: 做什么工作
调度器 Scheduler: 搭配 Trigger和Job


import static org.quartz.JobBuilder.newJob;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.Trigger;

import org.quartz.impl.StdSchedulerFactory;

 

public class TestQuartz {

    public static void main(String[] args) throws Exception{

            //创建调度器

            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

 

            //定义一个触发器

            Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义名称和所属的组

                .startNow()

                .withSchedule(simpleSchedule()

                    .withIntervalInSeconds(2) //每隔2秒执行一次

                    .withRepeatCount(10)) //总共执行11次(第一次执行不基数)

                         .build();

 

            //定义一个JobDetail

            JobDetail job = newJob(MailJob.class) //指定干活的类MailJob

                .withIdentity("mailjob1", "mailgroup") //定义任务名称和分组

                .usingJobData("email", "admin@10086.com") //定义属性

                .build();

           

            //调度加入这个job

            scheduler.scheduleJob(job, trigger);

            //启动

            scheduler.start();

            //等待20秒,让前面的任务都执行完了之后,再关闭调度器

            Thread.sleep(20000);

            scheduler.shutdown(true);

    }

}

 

MailJob是实际干活的类

public class MailJob implements Job {

    public void execute(JobExecutionContext context) throws JobExecutionException {

        JobDetail detail = context.getJobDetail();

        String email = detail.getJobDataMap().getString("email");

        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

        String now = sdf.format(new  Date());

        System.out.printf("给邮件地址 %s 发出了一封定时邮件, 当前时间是: %s%n" ,email, now);

    }

}

 

2.job的组成

Job 其实是由 3 个部分组成:
JobDetail: 用于描述这个Job是做什么的
实现Job的类: 具体干活的
JobDataMap: 给 Job 提供参数用的

 

JobDetail可以使用usingJobData(key,value)和getJobDataMap.put(key,value)来给参数赋值;

为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

注意:Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。

解决方法有两种,第一种是在Spring中这时需要设置concurrent的值为false, 禁止并发执行。

 <property name="concurrent" value="false" />;第二种是在Job的实现类上加@DisallowConcurrentExecution的注释。

@DisallowConcurrentExecution 禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition(由JobDetail定义), 但是可以同时执行多个不同的JobDetail。

 

3.job异常

任务里发生异常是很常见的。

异常处理办法通常是两种:
1). 当异常发生,那么就通知所有管理这个Job的调度,停止运行它;

JobExecutionException je =new JobExecutionException(e);

je.setUnscheduleAllTriggers(true);


2). 当异常发生,修改一下参数,马上重新运行。

JobExecutionException je =new JobExecutionException(e);

je.setRefireImmediately(true);

 

4.Trigger

Trigger 就是触发器的意思,用来指定什么时间开始触发,触发多少次,每隔多久触发一次.
SimpleTrigger 可以方便的实现一系列的触发机制。

触发器的

.startTime设置什么时候启动

Date startTime = DateBuilder.nextGivenSecondDate(null, 8);//每8s进行一次

.withRepeatCount是设置重复的次数,.repeatForever()是永久执行

 

5. CronTrigger

Cron 是Linux下的一个定时器,功能很强大,但是表达式更为复杂

如:.withSchedule(cronSchedule("0/2 * * * * ?"))表示每2秒执行一次,是不是有点懵逼,别急,其中0/2表示每两秒

理解Corn

Corn由7个部分组成,每个部分就如图所示分别对应秒 分 一直到年,可以不用写到7位
星号():可用在所有字段中,表示对应时间域的每一个时刻,例如, 在分钟字段时,表示“每分钟”;
问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;

 

6. Quartz API

Quartz的API的风格在2.x以后,采用的是DSL风格(通常意味着fluent interface风格),就是示例中newTrigger()那一段东西。它是通过Builder实现的,就是以下几个。(** 下面大部分代码都要引用这些Builder ** )

//job相关的builder
import static org.quartz.JobBuilder.*;
//trigger相关的builder
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DailyTimeIntervalScheduleBuilder.*;
import static org.quartz.CalendarIntervalScheduleBuilder.*;
//日期相关的builder
import static org.quartz.DateBuilder.*;

DSL风格写起来会更加连贯,畅快,而且由于不是使用setter的风格,语义上会更容易理解一些。对比一下:

JobDetail jobDetail=new JobDetailImpl("jobDetail1","group1",HelloQuartz.class);
jobDetail.getJobDataMap().put("name", "quartz");
SimpleTriggerImpl trigger=new SimpleTriggerImpl("trigger1","group1");
trigger.setStartTime(new Date());
trigger.setRepeatInterval(1);
trigger.setRepeatCount(-1);

关于name和group

JobDetail和Trigger都有name和group。

name是它们在这个sheduler里面的唯一标识。如果我们要更新一个JobDetail定义,只需要设置一个name相同的JobDetail实例即可。

group是一个组织单元,sheduler会提供一些对整组操作的API,比如 scheduler.resumeJobs()。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值