任务调度是指基于 给定时间点,给定时间间隔 或者 给定执行次数 自动执行任务。
方式1:通过 Thread 来实现
例如如下的代码,可以每隔 1000 毫秒做一次打印操作。
public class Job_Schedule_Test1 { public static void main(String[] args) { new JobThread().start(); } } class JobThread extends Thread { public void run() { while (true) { System.out.println("Test: " + Calendar.getInstance().getTime()); try { Thread.sleep(1000); } catch (Exception e) { } } } }
输出如下:
Test: Wed Feb 22 14:33:57 CST 2017
Test: Wed Feb 22 14:33:58 CST 2017
Test: Wed Feb 22 14:33:59 CST 2017
Test: Wed Feb 22 14:34:00 CST 2017
Test: Wed Feb 22 14:34:01 CST 2017
方式2:通过 Timer 来实现
- 自定义一个任务,继承于
TimerTask
,重写run
方法 - 利用
java.util.Timer
实现任务调度
public class Job_Schedule_Test2 { public static void main(String[] args) { Timer timer = new Timer(); long delay = 2000; long interval = 1000; // 从现在开始 2 秒钟之后启动,每隔 1 秒钟执行一次 timer.schedule(new JobTask(), delay, interval); } } class JobTask extends TimerTask { public void run() { System.out.println("Test: " + Calendar.getInstance().getTime()); } }
输出如下:
Test: Wed Feb 22 15:02:15 CST 2017
Test: Wed Feb 22 15:02:16 CST 2017
Test: Wed Feb 22 15:02:17 CST 2017
Test: Wed Feb 22 15:02:18 CST 2017
Test: Wed Feb 22 15:02:19 CST 2017
Timer
的设计核心是一个 TaskList
和一个 TaskThread
。Timer
将接收到的任务丢到自己的 TaskList
中,TaskList
按照 Task
的最初执行时间进行排序。TimerThread
在创建 Timer
时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread
被唤醒并执行该任务。之后 TimerThread
更新最近一个要执行的任务,继续休眠。
Timer
的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
例如我们指定每隔 1000 毫秒执行一次任务,但是可能某个任务执行花了 5000 毫秒,因此导致后续的任务并不能按时启动执行。
方式3:通过 ScheduledExecutorService 来实现
鉴于 Timer
的上述缺陷,Java 5 推出了基于线程池设计的 ScheduledExecutorService
。
其设计思想是,每一个被调度的任务都会 由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。
需要注意的是,只有当任务的执行时间到来时,ScheduledExecutorService
才会真正启动一个线程,其余时间 ScheduledExecutorService
都是在轮询任务的状态。
public class Job_Schedule_Test3 { public static void main(String[] args) { ScheduledExecutorService service = Executors.newScheduledThreadPool(10); long delay = 2; long interval = 1; // 从现在开始 2 秒钟之后启动,每隔 1 秒钟执行一次 service.scheduleAtFixedRate( new JobTask2(), delay, interval, TimeUnit.SECONDS); } } class JobTask2 implements Runnable { public void run() { System.out.println("Test: " + Calendar.getInstance().getTime()); } }
输出如下:
Test: Wed Feb 22 15:19:05 CST 2017
Test: Wed Feb 22 15:19:06 CST 2017
Test: Wed Feb 22 15:19:07 CST 2017
Test: Wed Feb 22 15:19:08 CST 2017
Test: Wed Feb 22 15:19:09 CST 2017
用 ScheduledExecutorService 和 Calendar 实现复杂任务调度
Timer
和 ScheduledExecutor
都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。
比如,设置每星期二的 16:38:10 执行任务。我们可以借助 Calendar
间接实现该功能。
其核心在于根据当前时间推算出最近一个星期二 16:38:10 的绝对时间,然后计算与当前时间的时间差,作为调用 ScheduledExceutor
函数的参数。
具体参见 几种任务调度的 Java 实现方法与比较
方式4:通过 Quartz 来实现
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do.
示例如下:
public class QuartzJob implements org.quartz.Job { public QuartzJob() { } public void execute(JobExecutionContext arg0) throws JobExecutionException { System.out.println("Test: " + Calendar.getInstance().getTime()); } } import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import static org.quartz.JobBuilder.*; import static org.quartz.TriggerBuilder.*; import static org.quartz.SimpleScheduleBuilder.*; public class Job_Schedule_Test4 { public static void main(String[] args) throws SchedulerException { // Grab the Scheduler instance from the Factory Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // define the job and tie it to our MyJob class JobDetail job = newJob(QuartzJob.class) .withIdentity("job1", "group1") .build(); // Trigger the job to run now, and then repeat every 40 seconds Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(1) .repeatForever()) .build(); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job, trigger); // and start it off scheduler.start(); } }
方式5:通过 JCronTab 来实现
具体参见 几种任务调度的 Java 实现方法与比较
作者:专职跑龙套
链接:https://www.jianshu.com/p/aa7b7f50b4b0
來源:简书