方式一、使用java.util.Timer和java.util.TimerTask创建任务简单的任务调度。
1、其中Timer负责设定TimerTask的起始时间和间隔执行时间。只需要继承TimerTask,实现自己的run()方法,然后将其交给Timer去定时执行就可以了。
2、Timer的设计核心是一个TaskList和一个TaskThread。Timer将接收到的任务压入TaskList,任务执行排序是按照最初的执行时间排序的。
3、TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。
4、Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务
public class TimerTest extends TimerTask {
private String taskName = "";
public TimerTest(String taskName ) {
this.taskName = taskName ;
}
@Override
public void run() {
System.out.println("execute" + taskName );
}
public static void main(String[] args) {
Timer timer = new Timer();
long delay1 = 1 * 1000;
long period1 = 1000;
timer.schedule(new TimerTest("task1 start......"), delay1, period1);
long delay2 = 2 * 1000;
long period2 = 2000;
timer.schedule(new TimerTest("task2 start......"), delay2, period2);
}
}
方式二、使用java.util.concurrent.ScheduledExecutorService实现任务调度。
1、ScheduleAtFixedRate()每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …
2、ScheduleWithFixedDelay()每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay,...
3、每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。
4、需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。
public class ScheduledExecutorTest implements Runnable {
private String taskName = "";
public ScheduledExecutorTest(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println("execute" + taskName);
}
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
long initialDelay1 = 1;
long period1 = 1;
service.scheduleAtFixedRate(new ScheduledExecutorTest("task1 start......."), initialDelay1, period1,
TimeUnit.SECONDS);
long initialDelay2 = 1;
long delay2 = 1;
service.scheduleWithFixedDelay(new ScheduledExecutorTest("task2 start......."), initialDelay2, delay2,
TimeUnit.SECONDS);
}
}
方式三、用 ScheduledExecutor 和 Calendar 实现复杂任务调度。
1、Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。比如,设置每星期二的 16:38:10 执行任务。该功能使用 Timer 和 ScheduledExecutor 都不能直接实现,但我们可以借助 Calendar 间接实现该功能。
public class ScheduledExceutorTest2 extends TimerTask {
private String taskName = "";
public ScheduledExceutorTest2(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println("execute" + taskName);
}
/**
* 计算从当前时间currentDate开始,满足条件dayOfWeek, hourOfDay, minuteOfHour,
* secondOfMinite的最近时间
*
* @param currentDate
* @param dayOfWeek
* @param hourOfDay
* @param minuteOfHour
* @param secondOfMinite
* @return
*/
public Calendar getEarliestDate(Calendar currentDate, int dayOfWeek, int hourOfDay, int minuteOfHour,
int secondOfMinite) {
int currentWeekOfYear = currentDate.get(Calendar.WEEK_OF_YEAR);// 当前时间是一年中的第几周
int currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK);// 周
int currentHour = currentDate.get(Calendar.HOUR_OF_DAY);// 时
int currentMinute = currentDate.get(Calendar.MINUTE);// 分
int currentSecond = currentDate.get(Calendar.SECOND);// 秒
boolean weekLater = false;
if (dayOfWeek < currentDayOfWeek) {
weekLater = true;// 输入DAY_OF_WEEK小于当前DAY_OF_WEEK
} else if (dayOfWeek == currentDayOfWeek) {
if (hourOfDay < currentHour) {
weekLater = true;// DAY_OF_WEEK相等,输入HOUR_OF_DAY小于当前HOUR_OF_DAY
} else if (hourOfDay == currentHour) {
if (minuteOfHour < currentMinute) {
weekLater = true;// DAY_OF_WEEK相等,DAY_OF_WEEK相等,输入MINUTE小于当前MINUTE
} else if (minuteOfHour == currentSecond) {
if (secondOfMinite < currentSecond) {
weekLater = true;// DAY_OF_WEEK相等,DAY_OF_WEEK相等,MINUTE相等,输入SECOND小于当前SECOND
}
}
}
}
if (weekLater) {
// 设置当前日期中的WEEK_OF_YEAR为当前周推迟一周
currentDate.set(Calendar.WEEK_OF_YEAR, currentWeekOfYear + 1);
}
// 设置当前日期中的DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND为输入条件中的值。
currentDate.set(Calendar.DAY_OF_WEEK, dayOfWeek);
currentDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
currentDate.set(Calendar.MINUTE, minuteOfHour);
currentDate.set(Calendar.SECOND, secondOfMinite);
return currentDate;
}
public static void main(String[] args) {
ScheduledExceutorTest2 test = new ScheduledExceutorTest2("job1");
// 获取当前时间
Calendar currentDate = Calendar.getInstance();
long currentDateLong = currentDate.getTime().getTime();
System.out.println("Current Date = " + currentDate.getTime().toString());
// 计算满足条件的最近一次执行时间
Calendar earliestDate = test.getEarliestDate(currentDate, 3, 16, 38, 10);
long earliestDateLong = earliestDate.getTime().getTime();
System.out.println("Earliest Date = " + earliestDate.getTime().toString());
// 计算从当前时间到最近一次执行时间的时间间隔
long delay = earliestDateLong - currentDateLong;
// 计算执行周期为一星期
long period = 7 * 24 * 60 * 60 * 1000;
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
// 从现在开始delay毫秒之后,每隔一星期执行一次job1
service.scheduleAtFixedRate(test, delay, period, TimeUnit.MILLISECONDS);
}
}