Chinaunix首页 | 论坛 | 博客
  • 博客访问: 534911
  • 博文数量: 260
  • 博客积分: 10435
  • 博客等级: 上将
  • 技术积分: 1939
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-24 14:50
文章分类

全部博文(260)

文章存档

2011年(22)

2010年(209)

2009年(29)

我的朋友

分类: Java

2010-05-05 11:01:06

中已经有一个 timer 类可以用来进行执行计划,定时任务。我们所要做的只是继承 java.util.TimerTask 类。如下所示:

    package com.yourcompany.scheduling;

    import java.util.Calendar;

    import java.util.Date;

    import java.util.Timer;

    import java.util.TimerTask;

    public class ReportGenerator extends TimerTask {

    public void run() {

    System.out.println("Generating report");

    //TODO generate report

    }

    }

    class MainApplication {

    public static void main(String[] args) {

    Timer timer new Timer();

    Calendar date = Calendar.getInstance();

    date.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY);

    date.set(Calendar.HOUR, 0);

    date.set(Calendar.MINUTE, 0);

    date.set(Calendar.SECOND, 0);

    date.set(Calendar.MILLISECOND, 0);

    // Schedule to run every Sunday in midnight

    timer.schedule(new ReportGenerator(),  // TimerTask

    date.getTime(),          // Timer

    1000 * 60 * 60 * 24 * 7   // delay)

    };

    这里有几个问题,我们的类继承了TimerTask ,而timerTask 也是实现了 java.lang.Runnable 接口。我们所要做的只是在我们自己的类里重置 run() 方法。所以我们的TimerTask类其实是一种线程,但线程的调度往往不是按照我们希望来实现的,因为一些垃圾收集等原因,我们计划的时间点,却没有执 行必要的任务。这样会产生一些问题。虽然,Timer 类也提供了scheduleAtFixedRate() 方法用来在垃圾收集后能够快速的追上任务进度,但这个不一定是我们所需要的。特别是在 一些 J2EE 上 Timer 是无法控制的,因为它不在容器的权责范围内。另外的,这个任务调度也缺乏一些企业级所需要的 特殊 日期定制的功能,以及修改,查找任务的功能。

    这里我们要介绍的是一个开源项目:Quartz .

    Quartz 定义了两种 基本接口 Job 和 Trigger . 看名字也就知道,我们的任务必须实现 Job, 我们的时间触发器定义在 Trigger 内。 看一个例子也许能更快的了解他的使用方法:package com.yourcompany.scheduling;

    import org.quartz.*;

    public class QuartzReport implements Job {

    public void execute(JobExecutionContext cntxt) //必须实现的方法

    throws JobExecutionException {

    System.out.println("Generating report - " +

    cntxt.getJobDetail().getJobDataMap().get("type"));

    //TODO Generate report

    }

    public static void main(String[] args) {

    try {

    SchedulerFactory schedFact

    new org.quartz.impl.StdSchedulerFactory();

    Scheduler sched = schedFact.getScheduler();

    sched.start();

    JobDetail jobDetail = new JobDetail("Income Report",       // 任务名

    "Report Generation", // 任务组

    QuartzReport.class    //任务执行的类

    );

    jobDetail.getJobDataMap().put("type","FULL");

    CronTrigger trigger new CronTrigger(

    "Income Report",              //触发器名

    "Report Generation"          //触发器组

    );

    trigger.setCronExpression(     // 触发器时间设定

    "0 0 12 ? * SUN"

    );

    sched.scheduleJob(jobDetail, trigger); // 执行任务

    }

     catch (Exception e) {

    e.printStackTrace();

    }

这里面我们可以看到,当我们定义了任务执行 QuartzReport 类后,需要定一个Scheduler类用来执行计划任务。

    一个JobDetail 类来描述这个任务的信息,包括任务信息,任务所在组,任务执行的类。

    然后还要定义一个 触发器,类似的也包括触发器名,触发器所在组,触发器触发时间设定。

    最后是调度器Scheduler类执行计划任务。基本上一个计划任务执行的流程就完成了。

    当然,我们还看到了上面红色代表的内容,这些内容主要是提供在job方法执行的时候所需要的参数的提供。这里使用了JobDataMap 类,它其实就是实现了map的特殊应用的一个类,使用方法与Map 很相似。我们可以用 put() 输入参数。在Job类中使用cntxt.getJobDetail()。getJobDataMap()。get("type") 方法获取输入的参数的值。这里的cntxt 是 JobExecutionContext .就是包含任务执行上下文的一个信息类。这样我们的一个基本的任务执行就可以搞定了。

    触发器有两类:SimpleTrigger andCronTrigger. .SimpleTrigger主要提供了跟 java.util.Timer 类相似的功能……你可以在里面定义 任务的起始时间,终止时间,任务的执行次数,任务执行的中间间隔 . 而 CronTrigger类主要提供了更高级的任务调度时间设置,例如 每个星期天的早上7点  . CronTrigger的时间设置说明在最后来介绍。

    下面我们介绍一下在 J2EE 环境下如何来使用 Quartz .

    首先,我们要配置 web.xml ,添加 一下内容,主要是Quartz 的初始化,

   

    QuartzInitializer

    Quartz Initializer Servlet

    org.quartz.ee.servlet.QuartzInitializerServlet

    1

   

    然后还要有一个Quartz 的配置文件 quartz.properties 放置在 WEB-INF/classes目录下面。StdScheduleFactory()会读取它。配置如下#

    # Configure Main Scheduler Properties

    #

    org.quartz.scheduler.instanceName = TestScheduler

    org.quartz.scheduler.instanceId = one

    #

    # Configure ThreadPool

    #

    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

    org.quartz.threadPool.threadCount = 5

    org.quartz.threadPool.threadPriority = 4

    #

    # Configure JobStore

    #

    org.quartz.jobStore.misfireThreshold = 5000

    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

    这里我们使用的 RAMJobStore 方式,这样如果我们的web重启的话,我们所有未执行的任务信息都回丢失。当然,我们也有另外的选择,我们可以把这样的信息在数据库内,就是使用 JDBCJobStoreTX

    #

    # Configure ThreadPool

    #

    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

来自: 

    org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_

    #

    # Configure Datasources

     #

    org.quartz.dataSource.myDS.driver = org.postgresql.Driver

    org.quartz.dataSource.myDS.URL = jdbc:postgresql:dev

    org.quartz.dataSource.myDS.user = dejanb

    org.quartz.dataSource.myDS.password = org.quartz.dataSource.myDS.maxConnections 5

附:cronExpression配置说明

字段

 

允许值

 

允许的特殊字符

 

0-59

 

, - * /

 

0-59

 

, - * /

小时

 

0-23

 

, - * /

日期

 

1-31

 

, - * ? / L W C

月份

 

1-12 或者 JAN-DEC

 

, - * /

星期

 

1-7 或者 SUN-SAT

 

, - * ? / L C #

年(可选)

 

留空, 1970-2099

 

, - * /

Cron 的小小说明

表示方式

意义

"0 0 12 * * ?"

Fire at 12pm (noon) every day

"0 15 10 ? * *"

Fire at 10:15am every day

"0 15 10 * * ?"

Fire at 10:15am every day

"0 15 10 * * ? *"

Fire at 10:15am every day

"0 15 10 * * ? 2005"

Fire at 10:15am every day during the year 2005

"0 * 14 * * ?"

Fire every minute starting at 2pm and ending at 2:59pm, every day

"0 0/5 14 * * ?"

Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day

"0 0/5 14,18 * * ?"

Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day

"0 0-5 14 * * ?"

Fire every minute starting at 2pm and ending at 2:05pm, every day

"0 10,44 14 ? 3 WED"

Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.

"0 15 10 ? * MON-FRI"

Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday

"0 15 10 15 * ?"

Fire at 10:15am on the 15th day of every month

"0 15 10 L * ?"

Fire at 10:15am on the last day of every month

"0 15 10 ? * 6L"

Fire at 10:15am on the last Friday of every month

"0 15 10 ? * 6L"

Fire at 10:15am on the last Friday of every month

"0 15 10 ? * 6L 2002-2005"

Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005

"0 15 10 ? * 6#3"

Fire at 10:15am on the third Friday of every month


这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需求

     Timer类是用来执行任务的类,它接受一个TimerTask做参数

     Timer有两种执行任务的模式,最常用的是schedule,它可以以两种方式执行任务:1:在某个时间(Data),2:在某个固定的时间之后(int delay).这两种方式都可以指定任务执行的频率.看个简单的例子:



import java.io.IOException;
import java.util.Timer;

public class TimerTest {
       
    
public static void main(String[] args){
        Timer timer 
= new Timer();
        timer.schedule(
new MyTask(), 10002000);//在1秒后执行此任务,每次间隔2秒,如果传递一个Data参数,就可以在某个固定的时间执行这个任务.
        
while(true){//这个是用来停止此任务的,否则就一直循环执行此任务了
            
try {
                
int ch = System.in.read();
                
if(ch-'c'==0){
                    timer.cancel();//使用这个方法退出任务
                    
                }

            }
 catch (IOException e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }

    
    
    
static class MyTask extends java.util.TimerTask{

        @Override
        
public void run() {
            
// TODO Auto-generated method stub
            System.out.println("________");
        }

    }

    
    
    
    
}



    如果你使用的是JDK 5+,还有一个scheduleAtFixedRate模式可以用,在这个模式下,Timer会尽量的让任务在一个固定的频率下运行,举例说明:在上面的 例子中,我们想让MyTask在1秒钟后,每两秒钟执行一次,但是因为java不是实时的(其实java实时性很差.....),所以,我们在上个程序中 表达的原义并不能够严格执行.如果我们调用的是scheduleAtFixedRate,那么,Timer会尽量让你的Task执行的频率保持在2秒一 次.运行上面的程序,假设使用的是scheduleAtFixedRate,那么下面的场景就是可能的:1秒钟后,MyTask 执行一次,因为系统繁 忙,之后的2.5秒后MyTask 才得以执行第二次,然后,Timer记下了这个延迟,并尝试在下一个任务的时候弥补这个延迟,那么,1.5秒 后,MyTask 将执行的三次."以固定的频率而不是固定的延迟时间去执行一个任务"

果然很方便吧^_^

下面给出一个复杂点的例子,其中告诉大家怎么退出单个TimerTask,怎么退出所有Task

package MyTimerTest;

import java.io.IOException;
import java.util.Timer;


/*
 * 本类给出了使用Timer和TimerTaske的主要方法,其中包括定制任务,添加任务
 * 退出任务,退出定时器.
 * 因为TimerTask的status域是包级可访问的,所以没有办法在java.util.包外
 * 得到其状态,这对编程造成一些不便 .我们不能判断某个Task的状态了.
 * 
 
*/


public class TimerTest {

    
public static void main(String[] args) {
        Timer timer 
= new Timer();
        MyTask myTask1 
= new MyTask();
        MyTask myTask2 
= new MyTask();
        myTask2.setInfo(
"myTask-2");
        timer.schedule(myTask1, 
10002000);
        timer.scheduleAtFixedRate(myTask2, 
20003000);
        
while (true{
            
try {
                
byte[] info = new byte[1024];
                
int len = System.in.read(info);
                String strInfo 
= new String(info, 0, len, "GBK");//从控制台读出信息
                if (strInfo.charAt(strInfo.length() - 1== ' '{
                    strInfo 
= strInfo.substring(0, strInfo.length() - 2);
                }

                
if (strInfo.startsWith("Cancel-1")) {
                    myTask1.cancel();
//退出单个任务
                    
// 其实应该在这里判断myTask2是否也退出了,是的话就应该break.但是因为无法在包外得到
                    
// myTask2的状态,所以,这里不能做出是否退出循环的判断.
                }
 else if (strInfo.startsWith("Cancel-2")) {
                    myTask2.cancel();
                }
 else if (strInfo.startsWith("Cancel-All")) {
                    timer.cancel();
//退出Timer
                    break;
                }
 else {
                    
// 只对myTask1作出判断,偷个懒^_^
                    myTask1.setInfo(strInfo);
                }

            }
 catch (IOException e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }


    
static class MyTask extends java.util.TimerTask {
        String info 
= "^_^";

        @Override
        
public void run() {
            
// TODO Auto-generated method stub
            System.out.println(info);
        }


        
public String getInfo() {
            
return info;
        }


        
public void setInfo(String info) {
            
this.info = info;
        }


    }


}


阅读(938) | 评论(0) | 转发(0) |
0

上一篇:virtual box usb

下一篇:linux top

给主人留下些什么吧!~~