需求:程序需要定时执行,比如说在某个时间报时。现在功能大概实现了。现在问题是:如何在某个特定时间结束呢?比如说在每天早上7点执行,在8点结束,然后下次开始也是在7点执行,在8点结束。大家看看我的程序有什么问题?1.通过指定一个固定的执行频率或者固定的执行时间间隔,Timer 可以对重复执行的任务进行计划。不过,有许多应用程序要求更复杂的计划。例如,每天清晨在同一时间发出叫醒铃声的闹钟不能简单地使用固定的计划频率 86400000 毫秒(24 小时),因为在钟拨快或者拨慢(如果您的时区使用夏令时)的那些天里,叫醒可能过晚或者过早。解决方案是使用日历算法计算每日事件下一次计划发生的时间。而这正是计划框架所支持的。
package com.digi.timer.scheduling;import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;public class AlarmClock {

private final Scheduler scheduler = new Scheduler();
private final SimpleDateFormat simpleDateFormate = new SimpleDateFormat("dd MM yyyy HH:mm:ss:SSS");
private final int hourOfDay,minutes,second;

//private static final int C_SCHEDULE_HOUR = 13;

public AlarmClock(int hourOfDay,int minutes,int second) {
this.hourOfDay = hourOfDay;
this.minutes = minutes;
this.second = second;
}

public void start() {
        scheduler.schedule(new SchedulerTask() {
        
            public void run() {
                soundAlarm();
                scheduler.cancle();
            }
            private void soundAlarm() {
                System.out.println("Wake up! " +
                    "It's " + simpleDateFormate.format(new Date()));
                // Start a new thread to sound an alarm...
            }
        }, new DailyIterator(hourOfDay, minutes, second));
    }

public static void main(String[] args) {
AlarmClock alarmClock = new AlarmClock(10,0,0);
alarmClock.start();
}}
AlarmClock 实例拥有一个 Scheduler (而不是 Timer)实例,用于提供必要的计划。启动后,这个闹钟对 SchedulerTask (而不是 TimerTask)进行调度用以发出报警声。这个闹钟不是计划一个任务在固定的延迟时间后执行,而是用 DailyIterator 类描述其计划。在这里,它只是计划任务在每天上午 7:00 执行。2.DailyIterator 实现了 ScheduleIterator,这是一个将 SchedulerTask 的计划执行时间指定为一系列 java.util.Date 对象的接口。然后 next() 方法按时间先后顺序迭代 Date 对象。返回值 null 会使任务取消(即它再也不会运行)―― 这样的话,试图再次计划将会抛出一个异常
package com.digi.timer.scheduling;import java.util.Calendar;
import java.util.Date;public class DailyIterator implements ScheduleIterator { private final int hourOfDay, minute, second;
private final Calendar calendar = Calendar.getInstance(); public DailyIterator(int hourOfDay, int minute, int second) {
this(hourOfDay, minute, second, new Date());
} public DailyIterator(int hourOfDay, int minute, int second, Date date) {
this.hourOfDay = hourOfDay;
this.minute = minute;
this.second = second;
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.MILLISECOND, 0);
if (!calendar.getTime().before(date)) {
calendar.add(Calendar.DATE, -1);
}
} public Date next() {
calendar.add(Calendar.DATE, 1);
return calendar.getTime();
}}
DailyIterator 的 next() 方法返回表示每天同一时间(上午 7:00)的 Date 对象,如清单 4 所示。所以,如果对新构建的 next() 类调用 next(),那么将会得到传递给构造函数的那个日期当天或者后面一天的 7:00 AM。再次调用 next() 会返回后一天的 7:00 AM,如此重复。为了实现这种行为,DailyIterator 使用了 java.util.Calendar 实例。构造函数会在日历中加上一天,对日历的这种设置使得第一次调用 next() 会返回正确的 Date。注意代码没有明确地提到夏令时修正,因为 Calendar 实现(在本例中是 GregorianCalendar)负责对此进行处理,所以不需要这样做。
3.
package com.digi.timer.scheduling;import java.util.Date;public interface ScheduleIterator {

public Date next();}
4。ScheduleIterator 接口,构成这个框架的还有另外两个类 ―― Scheduler 和 SchedulerTask 。这些类实际上在内部使用 Timer 和 SchedulerTask,因为计划其实就是一系列的单次定时器。
package com.digi.timer.scheduling;import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;public class Scheduler {

class SchedulerTimerTask extends TimerTask {

private SchedulerTask schedulerTask;
private ScheduleIterator iterator;

public SchedulerTimerTask(SchedulerTask schedulerTask,ScheduleIterator iterator) {
this.schedulerTask = schedulerTask;
this.iterator = iterator;
} @Override
public void run() {
 schedulerTask.run();
         reschedule(schedulerTask, iterator); }

} private final Timer timer = new Timer();

public Scheduler() {}

public void cancle() {
timer.cancel();
}

public void schedule(SchedulerTask schedulerTask, ScheduleIterator iterator) {
Date time = iterator.next();
if( time == null ) {
schedulerTask.cancel();
} else {
synchronized(schedulerTask.lock) {
                if (schedulerTask.state != SchedulerTask.VIRGIN) {
                  throw new IllegalStateException("Task already scheduled " + "or cancelled");
                }
                schedulerTask.state = SchedulerTask.SCHEDULED;
                schedulerTask.timerTask =
                    new SchedulerTimerTask(schedulerTask, iterator);
                timer.schedule(schedulerTask.timerTask, time);
            } }
} private void reschedule(SchedulerTask schedulerTask,
            ScheduleIterator iterator) {        Date time = iterator.next();
        if (time == null) {
            schedulerTask.cancel();
        } else {
            synchronized(schedulerTask.lock) {
                if (schedulerTask.state != SchedulerTask.CANCELLED) {
                    schedulerTask.timerTask =
                        new SchedulerTimerTask(schedulerTask, iterator);
                    timer.schedule(schedulerTask.timerTask, time);
                }
            }
        }
    }
}
5.
package com.digi.timer.scheduling;import java.util.TimerTask;public abstract class SchedulerTask implements Runnable {    final Object lock = new Object();    int state = VIRGIN;
    static final int VIRGIN = 0;
    static final int SCHEDULED = 1;
    static final int CANCELLED = 2;    TimerTask timerTask;    protected SchedulerTask() {
    }    public abstract void run();    public boolean cancel() {
        synchronized(lock) {
            if (timerTask != null) {
                timerTask.cancel();
            }
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }    public long scheduledExecutionTime() {
        synchronized(lock) {
         return timerTask == null ? 0 : timerTask.scheduledExecutionTime();
        }
    }}
就像煮蛋计时器,Scheduler 的每一个实例都拥有 Timer 的一个实例,用于提供底层计划。Scheduler 并没有像实现煮蛋计时器时那样使用一个单次定时器,它将一组单次定时器串接在一起,以便在由 ScheduleIterator 指定的各个时间执行 SchedulerTask 类。考虑 Scheduler 上的 public schedule() 方法 ―― 这是计划的入口点,因为它是客户调用的方法(在 取消任务 一节中将描述仅有的另一个 public 方法 cancel())。通过调用 ScheduleIterator 接口的 next(),发现第一次执行 SchedulerTask 的时间。然后通过调用底层 Timer 类的单次 schedule() 方法,启动计划在这一时刻执行。为单次执行提供的 TimerTask 对象是嵌入的 SchedulerTimerTask 类的一个实例,它包装了任务和迭代器(iterator)。在指定的时间,调用嵌入类的 run() 方法,它使用包装的任务和迭代器引用以便重新计划任务的下一次执行。reschedule() 方法与 schedule() 方法非常相似,只不过它是 private 的,并且执行一组稍有不同的 SchedulerTask 状态检查。重新计划过程反复重复,为每次计划执行构造一个新的嵌入类实例,直到任务或者调度程序被取消(或者 JVM 关闭)。类似于 TimerTask,SchedulerTask 在其生命周期中要经历一系列的状态。创建后,它处于 VIRGIN 状态,这表明它从没有计划过。计划以后,它就变为 SCHEDULED 状态,再用下面描述的方法之一取消任务后,它就变为 CANCELLED 状态。管理正确的状态转变 ―― 如保证不对一个非 VIRGIN 状态的任务进行两次计划 ―― 增加了 Scheduler 和 SchedulerTask 类的复杂性。在进行可能改变任务状态的操作时,代码必须同步任务的锁对象。

解决方案 »

  1.   

    看看这个,是个非常优秀和好用的开源软件。Quartz is a full-featured, open source job scheduling system that can be integrated with, or used along side virtually any J2EE or J2SE application。
    http://www.opensymphony.com/quartz/
      

  2.   


    楼主你看看这个,很好的,配置很灵活,看了一下你的需求通过quartz应该都可以实现
    顶一个
      

  3.   

    谢谢,我在看呢。我程序也能在指定时间内运行,只能不能在指定时间内停止。我在AlarmClock中加了几行代码,希望在指定时间内结束,尝试了下。还是不行。
     private void soundAlarm() {
                 int i = 0;
                 Calendar ca = Calendar.getInstance();
                 while(flag) {
                 System.out.println("i = " + i);
                 i++;
                 if(C_SCHEDULE_HOUR == ca.get(Calendar.HOUR_OF_DAY)|| i == 10000) {
                 flag = false;
                 }
                 }
                }
      

  4.   

    windows用计划任务,简单方便,
      

  5.   

    love csdn ,love brother。
    2010快到了,感谢csdn上的哥们送给我Quartz Job Scheduling Framework