第一种调度方法:Timer

使用Timer 实现任务调度的核心类是 Timer 和 TimerTask。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个TimerTask 的继承类,实现自己的 run 方法,然后将其丢给 Timer 去执行即可。 Timer 的设计核心是一个 TaskList和一个TaskThread。Timer 将接收到的任务丢到自己的 TaskList 中,TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后TimerThread 更新最近一个要执行的任务,继续休眠。 Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会 影响到之后的任务。

package com.ibm.scheduler;   
import java.util.Timer;   
import java.util.TimerTask;   
public class TimerTest extends TimerTask {   
private String jobName = "";     
public TimerTest(String jobName) {   
super();   
this.jobName = jobName;   
}     
@Override   
public void run() {   
System.out.println("execute " + jobName);   
}    
public static void main(String[] args) {   
Timer timer = new Timer();   
long delay1 = 1 * 1000;   
long period1 = 1000;   
// 从现在开始 1 秒钟之后,每隔 1 秒钟执行一次 job1   
timer.schedule(new TimerTest("job1"), delay1, period1);   
long delay2 = 2 * 1000;   
long period2 = 2000;   
// 从现在开始 2 秒钟之后,每隔 2 秒钟执行一次 job2   
timer.schedule(new TimerTest("job2"), delay2, period2);   
}   
}   
Output:   
execute job1   
execute job1   
execute job2   
execute job1   
execute job1   
execute job2

第二种调度方法:ScheduledExecutor

鉴于Timer 的上述缺陷,Java 5 推出了基于线程池设计的 ScheduledExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需 要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。

package com.ibm.scheduler;  
import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
  
public class ScheduledExecutorTest implements Runnable {  
    private String jobName = "";  
    public ScheduledExecutorTest(String jobName) {  
        super();  
        this.jobName = jobName;  
    }  
  
    @Override  
    public void run() {  
        System.out.println("execute " + jobName);  
    }  
  
    public static void main(String[] args) {  
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);  
        long initialDelay1 = 1;  
        long period1 = 1;  
        // 从现在开始1秒钟之后,每隔1秒钟执行一次job1  
        service.scheduleAtFixedRate(  
                new ScheduledExecutorTest("job1"), initialDelay1,  
                period1, TimeUnit.SECONDS);  
  
        long initialDelay2 = 1;  
        long delay2 = 1;  
        // 从现在开始2秒钟之后,每隔2秒钟执行一次job2  
        service.scheduleWithFixedDelay(  
                new ScheduledExecutorTest("job2"), initialDelay2,  
                delay2, TimeUnit.SECONDS);  
    }  
}  
Output:  
execute job1  
execute job1  
execute job2  
execute job1  
execute job1 

execute job2

以上代码展示了 ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。ScheduleAtFixedRate 每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …;ScheduleWithFixedDelay 每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay,

initialDelay+executeTime+delay, nitialDelay+2*executeTime+2*delay。由此可见,ScheduleAtFixedRate 是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。 

第三种调度方法:Quartz

Quartz 可以满足更多更复杂的调度需求,首先让我们看看如何用 Quartz 实现每星期二 16:38 的调度安排: 

package com.ibm.scheduler;  
import java.util.Date;   
import org.quartz.Job;  
import org.quartz.JobDetail;  
import org.quartz.JobExecutionContext;  
import org.quartz.JobExecutionException;  
import org.quartz.Scheduler;  
import org.quartz.SchedulerFactory;  
import org.quartz.Trigger;  
import org.quartz.helpers.TriggerUtils;  
  
public class QuartzTest implements Job {  
  
    @Override  
    //该方法实现需要执行的任务  
    public void execute(JobExecutionContext arg0) throws 


JobExecutionException {  
        System.out.println("Generating report - "  
                + arg0.getJobDetail().getFullName() + ", type ="  
                + arg0.getJobDetail().getJobDataMap().get("type"));  
        System.out.println(new Date().toString());  
    }  
    public static void main(String[] args) {  
        try {  
            // 创建一个Scheduler  
            SchedulerFactory schedFact =   
            new org.quartz.impl.StdSchedulerFactory();  
            Scheduler sched = schedFact.getScheduler();  
            sched.start();  
            // 创建一个JobDetail,指明name,groupname,以及具体的Job类名,  
            //该Job负责定义需要执行任务  
            JobDetail jobDetail = new JobDetail("myJob", "myJobGroup",  
                    QuartzTest.class);  
            jobDetail.getJobDataMap().put("type", "FULL");  
            // 创建一个每周触发的Trigger,指明星期几几点几分执行  
            Trigger trigger = TriggerUtils.makeWeeklyTrigger(3, 16, 38);  
            trigger.setGroup("myTriggerGroup");  
            // 从当前时间的下一秒开始执行  
            trigger.setStartTime(TriggerUtils.getEvenSecondDate(new Date
()));  
            // 指明trigger的name  
            trigger.setName("myTrigger");  
            // 用scheduler将JobDetail与Trigger关联在一起,开始调度任务  
            sched.scheduleJob(jobDetail, trigger);  
  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}   
Output:  
Generating report - myJobGroup.myJob, type =FULL  
Tue Feb 8 16:38:00 CST 2011  
Generating report - myJobGroup.myJob, type =FULL  
Tue Feb 15 16:38:00 CST 2011
 

以上代码非常简洁地实现了一个上述复杂的任务调度。Quartz 设计的核心类包括 Scheduler, Job 以及 Trigger。其中,Job 负责定义需要执行的任务,Trigger 负责设置调度策略,Scheduler 将二者组装在一起,并触发任务开始执行。 Job使用者只需要创建一个 Job 的继承类,实现 execute 方法。JobDetail 负责封装 Job 以及 Job 的属性,并将其提供给 Scheduler 作为参数。每次 Scheduler 执行任务时,首先会创建一个 Job 的实例,然后再调用 execute 方法执行。Quartz 没有为 Job 设计带参数的构造函数,因此需要通过额外的 JobDataMap 来存储 Job 的属性。Trigger 的作用是设置调度策略。Quartz 设计了多种类型的 Trigger,其中最常用的是 SimpleTrigger 和CronTrigger。 SimpleTrigger 适用于在某一特定的时间执行一次,或者在某一特定的时间以某一特定时间间隔执行多次。上述功能决定了 SimpleTrigger 的参数包括 start-time, end-time, repeat count, 以及 repeat interval。 Repeat count 取值为大于或等于零的整数,或者常量 SimpleTrigger.REPEAT_INDEFINITELY。Repeat interval 取值为大于或等于零的长整型。当 Repeat interval 取值为零并且 Repeat count 取值大于零时,将会触发任务的并发执行。Start-time 与 dnd-time 取值为 java.util.Date。当同时指定 end-time 与 repeat count 时,优先考虑 end-time。一般地,可以指定 end-time,并设定 repeat count 为 REPEAT_INDEFINITELY。CronTrigger 的用途更广,相比基于特定时间间隔进行调度安排的 SimpleTrigger,CronTrigger 主要适用于基于日历的调度安排。例如:每星期二的 16:38:10 执行,每月一号执行,以及更复杂的调度安排等。

CronTrigger 同样需要指定 start-time 和 end-time,其核心在于 Cron 表达式,
由七个字段组成: 
Seconds 
Minutes 
Hours 
Day-of-Month 
Month 
Day-of-Week 
Year (Optional field)
举例如下: 
创建一个每三小时执行的 CronTrigger,且从每小时的整点开始执行: 
0 0 0/3  * * ? 
创建一个每十分钟执行的 CronTrigger,且从每小时的第三分钟开始执行: 
0 3/10 * * * ? 
创建一个每周一,周二,周三,周六的晚上 20:00 到 23:00,每半小时执行一次的 
CronTrigger: 
0 0/30 20-23 ? * MON-WED,SAT 
创建一个每月最后一个周四,中午 11:30-14:30,每小时执行一次的 trigger: 
0 30 11-14/1 ? * 5L

通配符 * 表示该字段可接受任何可能取值。例如 Month 字段赋值 * 表示每个月,Day-of-Week 字段赋值 * 表示一周的每天。 / 表示开始时刻与间隔时段。例如 Minutes 字段赋值 2/10 表示在一个小时内每 20 分钟执行一次,从第 2 分钟开始。 ? 仅适用于 Day-of-Month 和 Day-of-Week。? 表示对该字段不指定特定值。

转载:http://blog.csdn.net/china2010pan/article/details/7401948