`

ScheduledExecutor 和 Calendar 实现复杂任务调度

 
阅读更多

Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。比如,设置每星期二的 16:38:10 执行任务。该功能使用 Timer 和 ScheduledExecutor 都不能直接实现,但我们可以借助 Calendar 间接实现该功能。


清单 3. 使用 ScheduledExcetuor 和 Calendar 进行任务调度

package com.ibm.scheduler;

import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExceutorTest2 extends TimerTask {

	private String jobName = "";

	public ScheduledExceutorTest2(String jobName) {
		super();
		this.jobName = jobName;
	}

	@Override
	public void run() {
		System.out.println("Date = "+new Date()+", execute " + jobName);
	}

	/**
	 * 计算从当前时间currentDate开始,满足条件dayOfWeek, hourOfDay, 
	 * minuteOfHour, secondOfMinite的最近时间
	 * @return
	 */
	public Calendar getEarliestDate(Calendar currentDate, int dayOfWeek,
			int hourOfDay, int minuteOfHour, int secondOfMinite) {
		//计算当前时间的WEEK_OF_YEAR,DAY_OF_WEEK, HOUR_OF_DAY, MINUTE,SECOND等各个字段值
		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);

		//如果输入条件中的dayOfWeek小于当前日期的dayOfWeek,则WEEK_OF_YEAR需要推迟一周
		boolean weekLater = false;
		if (dayOfWeek < currentDayOfWeek) {
			weekLater = true;
		} else if (dayOfWeek == currentDayOfWeek) {
			//当输入条件与当前日期的dayOfWeek相等时,如果输入条件中的
			//hourOfDay小于当前日期的
			//currentHour,则WEEK_OF_YEAR需要推迟一周	
			if (hourOfDay < currentHour) {
				weekLater = true;
			} else if (hourOfDay == currentHour) {
                 //当输入条件与当前日期的dayOfWeek, hourOfDay相等时,
                 //如果输入条件中的minuteOfHour小于当前日期的
				//currentMinute,则WEEK_OF_YEAR需要推迟一周
				if (minuteOfHour < currentMinute) {
					weekLater = true;
				} else if (minuteOfHour == currentSecond) {
                     //当输入条件与当前日期的dayOfWeek, hourOfDay, 
                     //minuteOfHour相等时,如果输入条件中的
                    //secondOfMinite小于当前日期的currentSecond,
                    //则WEEK_OF_YEAR需要推迟一周
					if (secondOfMinite < currentSecond) {
						weekLater = true;
					}
				}
			}
		}
		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) throws Exception {

		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);

	}
} 
Output:
Current Date = Wed Feb 02 17:32:01 CST 2011
Earliest Date = Tue Feb 8 16:38:10 CST 2011
Date = Tue Feb 8 16:38:10 CST 2011, execute job1
Date = Tue Feb 15 16:38:10 CST 2011, execute job1

  实现了每星期二 16:38:10 调度任务的功能。其核心在于根据当前时间推算出最近一个星期二 16:38:10 的绝对时间,然后计算与当前时间的时间差,作为调用 ScheduledExceutor 函数的参数。计算最近时间要用到 java.util.calendar 的功能。首先需要解释 calendar 的一些设计思想。Calendar 有以下几种唯一标识一个日期的组合方式:

 YEAR + MONTH + DAY_OF_MONTH 
 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK 
 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK 
 YEAR + DAY_OF_YEAR 
 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR 

 

上述组合分别加上 HOUR_OF_DAY + MINUTE + SECOND 即为一个完整的时间标识。本例采用了最后一种组合方式。输入为 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 以及当前日期 , 输出为一个满足 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 并且距离当前日期最近的未来日期。计算的原则是从输入的 DAY_OF_WEEK 开始比较,如果小于当前日期的 DAY_OF_WEEK,则需要向 WEEK_OF_YEAR 进一, 即将当前日期中的 WEEK_OF_YEAR 加一并覆盖旧值;如果等于当前的 DAY_OF_WEEK, 则继续比较 HOUR_OF_DAY;如果大于当前的 DAY_OF_WEEK,则直接调用 java.util.calenda 的 calendar.set(field, value) 函数将当前日期的 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 赋值为输入值,依次类推,直到比较至 SECOND。读者可以根据输入需求选择不同的组合方式来计算最近执行时间。

分享到:
评论

相关推荐

    Java调度原理及使用

    在Java中,有多种方式可以实现任务调度,包括`Timer`、`ScheduledExecutor`以及开源库如`Quartz`和`JCronTab`。 首先,`Timer`类是Java早期提供的定时任务调度器。它的使用非常直观,如代码清单1所示,通过`Timer`...

    几种任务调度的Java实现方法与比较

    本文由浅入深介绍四种任务调度的Java实现:ScheduledExecutor开源工具包Quartz开源工具包JCronTab此外,为结合实现复杂的任务调度,本文还将介绍Calendar的一些使用方法。Timer相信大家都已经非常熟悉java.util....

    quartzDemo任务调度例子

    通过`org.quartz.Scheduler`接口,我们可以注册任务和触发器,启动和停止调度器,以及查询和修改调度状态。 5. **配置Quartz** 通常,Quartz的配置通过XML文件完成,包括数据库连接、线程池大小、作业存储方式等。...

    任务调度Quartz框架

    通过灵活的Job和Trigger组合,以及持久化机制,开发者可以轻松地构建复杂而稳定的任务调度系统。同时,Quartz提供的监听器、插件和线程池等组件进一步增强了其可扩展性和定制性。 总的来说,无论是在小型项目还是...

    任务调度框架Quartz[收集].pdf

    Quartz通过解决多线程并发、时间规则制定、任务恢复、线程池管理等问题,简化了任务调度的复杂性。 在Quartz的核心概念中,有三个主要元素:Job、JobDetail和Trigger。Job接口是任务的抽象,只有一个`execute...

    Quartz任务调度快速入门

    Quartz通过其核心概念——调度器、任务和触发器——提供了一套完整且灵活的任务调度解决方案。开发者可以通过实现 `Job` 接口定义具体的任务逻辑,并通过配置 `Trigger` 和 `Calendar` 灵活地控制任务的执行时机。...

    quartz任务调度

    Quartz是一款开源的作业调度框架,它为Java应用程序提供了强大的定时任务...通过合理地设计和配置Job和Trigger,我们可以创建出满足各种需求的定时任务,无论是简单的周期性任务还是复杂的调度逻辑,Quartz都能够胜任。

    灵活、高效的分布式任务调度平台

    另外,合理的组件抽象设计使得开发一个组件非常简单,后续会提供更多组件,提供丰富的定时器(simple、calendar、daily、cron),强大的任务管理(编辑、暂停、恢复调度、立即运行、复制任务、删除等等),支持联动...

    Java任务调度框架Quartz1.8.6教程实例源代码

    Quartz支持简单和复杂的调度策略,如一次性执行、周期性执行或按照特定的时间表达式执行。其设计目标是为应用程序提供灵活且可靠的计划任务支持。 **二、Quartz的核心组件** 1. **Job**:工作,是Quartz中的基本...

    java每天实现定点执行任务

    在Java编程环境中,实现每天定点...`java.util.Timer`和`ScheduledExecutorService`适合简单的定时任务,而Quartz更适合大型项目,需要更复杂的调度规则。在实际应用中,还需考虑线程安全、异常处理和资源关闭等问题。

    net用Calendar实现blog日历

    在.NET框架中,利用Calendar控件来实现在博客(blog)平台上的日历功能,是一项既实用又具有挑战性的任务。这项技术的核心在于如何通过Calendar控件动态展示哪些日子有新发布的日志,并且允许用户通过点击特定日期,...

    小议时序调度Timer和Quartz

    Quartz的工作原理包括Scheduler、JobDetail、Trigger和Calendar等核心组件,它们协同工作以实现高度灵活的定时任务管理。 Quartz的配置和使用通常涉及以下几个步骤: 1. 引入依赖:在项目中添加Quartz的库。 2. ...

    基于quartz实现自定义时间的定时调度

    Quartz是一个强大的、完全开源的Java定时作业框架,它为创建简单或复杂的调度任务提供了丰富的功能。本篇将深入探讨如何基于Quartz实现自定义时间的定时调度。 一、Quartz简介 Quartz是由OpenSymphony开发的开源...

    Spring整合Quartz后的简单定时任务示例

    Job定义了要执行的任务,Trigger决定何时触发Job,而Calendar可以用于更复杂的调度规则,比如在某些日期或时间范围内不执行任务。 整合Spring和Quartz,我们首先需要在Spring配置文件中声明一个`...

    Quartz 固定时间间隔计划+Calendar和Cron

    4. **Quartz 源码解析**: 了解 Quartz 的源码有助于深入理解其工作原理,包括 JobStore(存储任务和触发器的地方)、Scheduler(负责管理和执行任务的中心组件)、以及 Trigger 和 JobDetail 的实现。通过源码分析,...

    quartz定时调度完整实例

    - Quartz是Cron-like和Calendar-based作业调度的Java实现,它允许开发人员在应用程序中定义、安排和执行任务。 - 作为轻量级的调度框架,Quartz可以非常方便地集成到任何Java应用中,无论是简单的单机应用还是大型...

    一个基于纯js实现的功能强大的JS Calendar (version 2.1)源码及例子

    除了基本的显示和隐藏日历功能,JS Calendar 2.1 还提供了一些高级API,如获取当前选中的日期、设置默认日期、关闭日历等,方便开发者进行更复杂的集成和定制。 综上所述,JS Calendar 2.1 是一个强大且灵活的...

    uni-app 插件 Calendar 日历多选 (不是范围选择)

    综上所述,uni-app插件Calendar日历多选是一个强大的工具,它提供了灵活的配置和丰富的事件回调,使得开发者能轻松地在uni-app项目中实现多日期选择功能。合理运用这些知识点,可以构建出高效且用户友好的日期选择...

    Java 之 Date 和 Calendar 实例

    在Java编程语言中,`Date`和`Calendar`类是处理日期和时间的核心组件。这两个类在不同的Java版本中有着不同的使用方式和功能,对于理解Java时间处理机制至关重要。本篇将深入探讨`Date`和`Calendar`类的实例应用。 ...

Global site tag (gtag.js) - Google Analytics