Java任务调度的几种解决方案(定时任务)
一、JDK原生定时工具Timer
1.定时任务调度:基于给定的时间点、给定的时间间隔、给定的执行次数的自动执行的任务
2.Timer位于java.util包下,内部仅包含一个后台线程(TimeThread)对多个业务任务(TimeTask)进行定时、定频率的调度。
3.schedule的四种用法和shceduleAtFixedRate的两种用法:
void schedule(TimerTask task, long delay);
void schedule(TimerTask task, Date time);
void schedule(TimerTask task, long delay, long period);
void schedule(TimerTask task, Date firstTime, long period);
void scheduleAtFixedRate(TimeTask task, long delay, long period );
void scheduleAtFixedRate(TimeTask task, Date firstTime, long period );
参数说明:
task:所要实行的任务(需要继承TimeTask的run()方法)
time/firstTime:首次执行任务的时间
period:周期性执行task的时间间隔,单位是毫秒
delay:执行task任务前延迟的时间,单位是毫秒
4.注意事项
4.1.如果time/firstTime指定在当前时间之前,立刻执行task;
4.2.scheduleAtFixedRate在任务开始时向后延迟一个period的时间执行下一次任务
而schedule在任务结束时向后延迟一个period的时间执行下一次任务
4.3.如果TimeTask抛出RuntimeException,那么Timer会停止所有任务的运行
4.4.单线程无法满足并发任务的需求,所有的任务都是串行执行意味着同一时间只能有一个任务得到执行
5.其他
Timer.cancel():终止Timer计时器,丢弃当前所有已安排的任务
TimerTask.cancel():终止TimeTask
Timer.purge():从计时器的任务列表中移除已取消的任务,并返回个数
6.Demo
public classTimerDemo {
public static voidmain(String[] args) {
Timer timer =new Timer();
//timer.schedule(new MyTask(),new Date(),20000);
timer.schedule(new MyTask(), 30000, 20000);
//timer.cancel();
}
}
class MyTaskextends TimerTask{
@Override
public voidrun() {
System.out.println("execute time start :"
+new SimpleDateFormat().format(
this.scheduledExecutionTime()
)
);
try{
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//this.cancel();
}
}
二、JDK对定时任务调度的线程池支持:ScheduleExecutorService
虽然ScheduleExcutorServiced对Timer进行了线程池的改进,但无法满足复杂的定时任务调度场景。
Demo:
public class ScheduleExecutorServiceDemo{
public static voidmain(String[] args) {
ScheduledExecutorService scheduledExecutorService=
Executors.newScheduledThreadPool(10);
scheduledExecutorService.scheduleAtFixedRate(
new MyTask(),2000,2000, TimeUnit.MILLISECONDS
);
}
}
classMyTask implementsRunnable{
@Override
public voidrun() {
System.out.println("execute time start :”+new Date());
}
}
三、Quartz(OpenSymphony)
1.作为Spring默认的调度框架,Quartz是纯Java实现的。
由于Quartz强大的调度功能、灵活的使用方式、还具有分布式集群能力,可以说Quartz出马轻松搞定一切任务调度服务。
2.相较于Timer,Quartz增加的功能:
2.1.持久性作业:保持调度定时的状态
2.2.作业管理:对调度作业进行有效的管理
3.Demo
public classPrintWordJob implementsJob {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException{
Calendar calendar= jobExecutionContext.getCalendar();
String dateFormat =new SimpleDateFormat("yy-mm-dd hh:mm:ss").format(calendar);
System.out.println("打印文字时间:"+dateFormat+",打印内容:Hello Job-"+new Random().nextInt(100));
}
}
public static void main(String[] args) throws SchedulerException, InterruptedException{
//1.创建调度器Scheduler
SchedulerFactory schedulerFactory=new StdSchedulerFactory();
Scheduler scheduler=schedulerFactory.getScheduler();
//2.创建JobDetail实例,并与PrintWordJob类绑定(Job执行内容)
JobDetail jobDetail= JobBuilder.newJob(PrintWordJob.class)
.withIdentity("myFirstJob","myGroup")
.build();
//3.构建Trigger实例,设置每隔三秒执行一次
Trigger trigger=TriggerBuilder.newTrigger()
.withIdentity("trigger1","triggerGroup1")
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()
).build();
//4.执行
scheduler.scheduleJob(jobDetail,trigger);
System.out.println("==========================scheduler start !======================");
scheduler.start();
//5.睡眠
TimeUnit.MINUTES.sleep(1);
scheduler.shutdown();
System.out.println("==========================scheduler shutdown !======================");
}
4.Job和JobDetail
4.1.Job是Quartz中的一个接口,接口下只有execute方法,在该方法中编写业务逻辑
4.2.JobDetail用来绑定Job并为实例提供属性:name、group、jobClass、jobDataMap
JobDetail绑定指定的Job,每次Scheduler调度执行一个Job的时候,首先会先拿到对应的Job并创建Job实例,再去执行Job中的exxcute方法的内容。任务执行结束后关联的Job对象实例会被释放,且会被JVM GC清除。
4.3.JobDetail的任务就是在Scheduler执行时创建一个新的Job实例,避免并发直接访问同一Job实例。
5.JobExecutionContext
JobExecutionContext包含Quartz运行时的环境以及Job本身的详细数据信息。当Schedule调度执行了一个Job的时候,就会将JobExecutionContext传递到该Job的execute()中,Job就可以通过JobExecutionCOntext对象获取信息。
6.JobDataMap
JobDataMap实现了JDK的Map接口,可以以key-value的形式存储数据。JobDetail、Trigger都可以使用JobDataMap来设置一些参数信息,Job执行execute()方法的时候,JobExecutionContext可以获取到JobDataMap里的信息。
Demo:
初始化JobDetail时:
JobDetail jobDetail= JobBuilder.newJob(PrintWordJob.class)
.withIdentity("myFirstJob", "myGroup")
.usingJobData("key", "value")
.build();
Job实例中获取
Object value= jobExecutionContext.getMergedJobDataMap().get("key");
7.Trigger:Trigger是Quartz的触发器,会去通知Scheduler合适去执行对应的Job
new Trigger().startAt():设置触发器首次被触发的时间;
new Trigger().endAt():设置触发器接触触发的时间;
new Trigger().startNow():设置触发器启动后即刻触发
7.1. TriggerWithSimpleSchedule
Demo:
Date startDate= new Date();
startDate.setTime(startDate.getTime() +5000);
Date endDate= new Date();
endDate.setTime(startDate.getTime() +5000);
Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.usingJobData("trigger1", "这是jobDetail1的trigger")
.startNow()//立即生效
.startAt(startDate)
.endAt(endDate)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//每隔1s执行一次
.repeatForever()).build();//一直执行
7.2. CronTrigger(常用)
CronTrigger基于日历的作业调度,而SimpleTrigger是精准指定间隔。
Cron表达式:[秒][分][时][日][月][周][年]
Demo:
CronTrigger cronTrigger= TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.usingJobData("trigger1", "这是jobDetail1的trigger")
.startNow()//立即生效
.startAt(startDate)
.endAt(endDate)
.withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
.build();