欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

定时器 实现

发布时间:2024/1/18 编程问答 37 豆豆
生活随笔 收集整理的这篇文章主要介绍了 定时器 实现 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
1、在应用开发中,经常需要一些周期性的操作,比如每5分钟检查一下新邮件等。对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。比如下面的代码每5分钟检查一遍是否有新邮件:

private java.util.Timer timer;
timer = new Timer(true);
timer.schedule(
new java.util.TimerTask() { public void run() { //server.checkNewMail(); 检查新邮件 } }, 0, 5*60*1000);


    使用这几行代码之后,Timer本身会每隔5分钟调用一遍server.checkNewMail()方法,不需要自己启动线程。Timer本身也是多线程同步的,多个线程可以共用一个Timer,不需要外部的同步代码。
在《The Java Tutorial》中有更完整的例子:
public class AnnoyingBeep {

Toolkit toolkit;
 Timer timer; 
 public AnnoyingBeep() {
  toolkit = Toolkit.getDefaultToolkit();
  timer = new Timer();
  timer.schedule(new RemindTask(), 0, 1*1000);

//initial delay  subsequent   rate
 }


 class RemindTask extends TimerTask {
  int numWarningBeeps = 3;
  public void run() {
   if (numWarningBeeps > 0) {
    toolkit.beep();
    System.out.println("Beep!");
    numWarningBeeps--;
   }
   else {
    toolkit.beep();
    System.out.println("Time´s up!");
    //timer.cancel(); //Not necessary because we call      

    System.exit System.exit(0);
    //Stops the AWT thread (and everything else)
   }
  }
 }
 ...
}
这段程序,每隔3秒响铃一声,并打印出一行消息。循环3次。程序输出如下:

IWAV0048I Java Bean com.AnnoyingBeep started with null constructor
Task scheduled.
Beep!
Beep! //one second after the first beep
Beep! //one second after the second beep
Time´s up! //one second after the third beep


Timer类也可以方便地用来作为延迟执行,比如下面的代码延迟指定的时间(以秒为单位)执行某操作。类似电视的延迟关机功能。


...public class ReminderBeep {
 ... public ReminderBeep(int seconds) {
  toolkit = Toolkit.getDefaultToolkit();
  timer = new Timer();
  timer.schedule(new RemindTask(), seconds*1000);
  }
  class RemindTask extends TimerTask {
   public void run() {
    System.out.println("Time´s up!");
    toolkit.beep();
    //timer.cancel(); //Not necessary because we call     System.exit System.exit(0);
    //Stops the AWT thread (and everything else)
   }
  }
 ...
 }
}

2、下面再写一个在WEB下定时器 由于系统核心是基于Web部署的,报表计算引擎也相应的部署在Tomcat容器上,因此如果想要借用Windows的任务计划来实现定时计算,就需要额外编写普通桌面应用程序接口,稍显复杂。于是就琢磨着想在Web上实现,经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

    下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

    我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):
  •     private java.util.Timer timer = null;
  •     public void contextInitialized(ServletContextEvent event) {
  •         timer = new java.util.Timer(true);
  •         event.getServletContext().log("定时器已启动");        
  •          timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);
  •         event.getServletContext().log("已经添加任务调度表");
  •     }
  •     public void contextDestroyed(ServletContextEvent event) {
  •         timer.cancel();
  •         event.getServletContext().log("定时器销毁");
  •     }

  •     以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

       下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:

  •     private static final int C_SCHEDULE_HOUR   = 0;
  •     private static boolean isRunning = false;
  •          private ServletContext context = null;
  •     public MyTask(ServletContext context) {
  •         this.context = context;
  •     }
  •     public void run() {
  •         Calendar cal = Calendar.getInstance();        
  •         if (!isRunning)  {           
  •             if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {            
  •                     isRunning = true;                
  •                 context.log("开始执行指定任务");
  •                 
  •                 //TODO 添加自定义的详细任务,以下只是示例
  •                 int i = 0;
  •                 while (i++ < 10) {
  •                     context.log("已完成任务的" + i + "/" + 10);
  •                 }
  •                 isRunning = false;
  •                 context.log("指定任务执行结束");               
  •             }            
  •         } else {
  •             context.log("上一次任务执行还未结束");
  •         }
  •     }

  •     上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

         到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:
        
             com.test.ContextListener
        
        当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

    2003-12-05 0:21:39 开始执行指定任务
    2003-12-05 0:21:39 已完成任务的1/10
        ……
    2003-12-05 0:21:39 已完成任务的10/10
    2003-12-05 0:21:39 指定任务执行结束
    由于系统核心是基于Web部署的,报表计算引擎也相应的部署在Tomcat容器上,因此如果想要借用Windows的任务计划来实现定时计算,就需要额外编写普通桌面应用程序接口,稍显复杂。于是就琢磨着想在Web上实现,经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

        下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

        我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):

  •     private java.util.Timer timer = null;
  •     public void contextInitialized(ServletContextEvent event) {
  •         timer = new java.util.Timer(true);
  •         event.getServletContext().log("定时器已启动");        
  •          timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);
  •         event.getServletContext().log("已经添加任务调度表");
  •     }
  •     public void contextDestroyed(ServletContextEvent event) {
  •         timer.cancel();
  •         event.getServletContext().log("定时器销毁");
  •     }

  •     以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

       下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:

  •     private static final int C_SCHEDULE_HOUR   = 0;
  •     private static boolean isRunning = false;
  •          private ServletContext context = null;
  •     public MyTask(ServletContext context) {
  •         this.context = context;
  •     }
  •     public void run() {
  •         Calendar cal = Calendar.getInstance();        
  •         if (!isRunning)  {           
  •             if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {            
  •                     isRunning = true;                
  •                 context.log("开始执行指定任务");
  •                 
  •                 //TODO 添加自定义的详细任务,以下只是示例
  •                 int i = 0;
  •                 while (i++ < 10) {
  •                     context.log("已完成任务的" + i + "/" + 10);
  •                 }
  •                 isRunning = false;
  •                 context.log("指定任务执行结束");               
  •             }            
  •         } else {
  •             context.log("上一次任务执行还未结束");
  •         }
  •     }

  •     上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

         到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:
       

    web.xml 里面<listener>
    <listener-class>com.bean.statListener</listener-class>
    </listener>


         
        当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

    2003-12-05 0:21:39 开始执行指定任务
    2003-12-05 0:21:39 已完成任务的1/10
        ……
    2003-12-05 0:21:39 已完成任务的10/10
    2003-12-05 0:21:39 指定任务执行结束

    3、实现定时

    public   class   myTask  
              extends   java.util.TimerTask   {  
          String   jobName;  
          private   int   i;  
          public   void   run()   {   //run   in   interface   Runnable  
              System.out.println(jobName);  
          }  
       
          public   myTask(String   jobName)   {  
              this.jobName   =   jobName;  
          }  
      }  
       
      //doTask.java    
       
      import   java.util.*;  
      import   java.io.*;  
       
      public   class   doTask   {  
          private   java.util.Timer   timer;  
          private   java.util.TimerTask   task;  
          public   doTask(java.util.TimerTask   task)   {  
              this.timer   =   new   Timer();  
              this.task   =   task;  
          }  
          public   void   start(int   delay,   int   internal)   {  
              timer.schedule(task,   delay   *   1000,   internal   *   1000);//利用timer.schedule方法  
          }  
       
          public   static   void   main(String[]   args)   {  
              java.util.TimerTask   task1   =   new   myTask("           Job   1");  
              java.util.TimerTask   task2=   new   myTask("Job   2");  
              doTask   pt   =   new   doTask(task1);  
              pt.start(1,3);  
              doTask   pt2   =   new   doTask(task2);  
              pt2.start(1,1);  
          }  
       
      }  

    4、C#结合singleton和线程做一个定时服务

    design pattern的singleton是一个虽然简单但很有用处的模式,它的作用就是使类只能有一个实例,不需要实例化,而提供一个唯一的全局切入点。如果再结合上线程,完全可以实现一个定时服务,不象Timer控件,它不仅可以应用在windows应用程序中,同样可以应用于web程序中,就象刚才蓝说的那种效果。看下面这个简单的例子吧。

    using System;
    using System.Threading ;

    namespace testall
    {
    /// <summary>
    /// 定时间隔
    /// </summary>
    /// <remarks>通过修改这个常量决定间隔多长时间做某件事</remarks>
    const int DELAY_TIMES = 1000 ;

    /// <summary>
    /// 一个计数器
    /// </summary>
    private int m_intCounter = 0;

    /// <summary>
    /// 是否退出
    /// </summary>
    private bool m_bCanExit = false ;

    /// <summary>
    /// 线程
    /// </summary>
    private Thread thread ;

    /// <summary>
    /// 自身实例
    /// </summary>
    /// <remarks>注意,这是实现singleton的关键</remarks>
    private static TestStatic instance = new TestStatic() ;

    public int Counter
    {
    get
    {
    return this.m_intCounter ;
    }
    set
    {
    this.m_intCounter = value ;
    }
    }

    public bool CanExit
    {
    set
    {
    this.m_bCanExit = value ;
    }
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public TestStatic()
    {
    //
    // TODO: Add constructor logic here
    //
    this.m_intCounter = 0 ;
    Console.WriteLine("constructor is running") ;
    this.thread = new Thread(new ThreadStart(ThreadProc)) ;
    thread.Name = "online user" ;
    thread.Start() ;
    Console.WriteLine("完毕") ;
    }


    /// <summary>
    /// 实现singleton的关键
    /// </summary>
    /// <returns>类本身的一个实例</returns>
    /// <remarks>唯一的全局切入点</remarks>
    public static TestStatic GetInstance()
    {
    return instance ;
    }

    /// <summary>
    /// 线程工作函数
    /// </summary>
    /// <remarks>想做什么写在这儿</remarks>
    private void ThreadProc()
    {
    while(!this.m_bCanExit)
    {
    this.m_intCounter ++ ;
    Console.WriteLine(this.m_intCounter.ToString()) ;
    Thread.Sleep(DELAY_TIMES) ;
    }
    }

    static void Main(string[] args)
    {
    //
    // TODO: Add code to start application here
    //
    Console.WriteLine(TestStatic.GetInstance().Counter.ToString()) ;
    Console.Read() ;
    TestStatic.GetInstance().CanExit = true ;
    }

    }

    }

    //

    import java.util.TimerTask;  
    import java.util.Calendar;  

    public class MyTask extends TimerTask 
    {  
        private static final int C_SCHEDULE_HOUR = 15;  
        private static boolean isRunning = false;  

        public MyTask() 
        {  
        }  

        public void run() 
        {  
            Calendar cal = Calendar.getInstance();  
            if (!isRunning) 
            {  
                //if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) 
                {  
                    isRunning = true;  
                    System.out.println(new java.util.Date() + "        任务开始");  
                    for (int i = 0 ; i < 100 ; i++ ) 
                    { 
                        System.out.println(new java.util.Date() + "          任务完成" + i + "/" + 100 );  
                    }  
                    isRunning = false;  
                    System.out.println(new java.util.Date() + "       所有任务完成!");  
                }  
            }  
            else  
            {  
                System.out.println(new java.util.Date() + "         任务退出!!!");  
            }  
        }  

    =====================================Test=========================================== 
    import java.util.TimerTask; 
    import java.util.Timer;  
    import javax.servlet.*; 
    public class Test{ 
        static Timer timer = null; 
        public static void main(String[] args){ 
            timer = new Timer(true); 
            System.out.println(new java.util.Date() + "      计时器已经启动..."); 
            timer.schedule(new MyTask() , 0 , 2*60*1000);//每2分钟执行一次 
            System.out.println(new java.util.Date() + "          计时器执行一次!!!!!"); 
        } 

    //

    JAVA-如何实现TIMER功能

    2004-11-8
    Author :Meanson Wang
    Email:meansonw@hotmail.com
    Date:2004-11-8

    JAVA里面要实现日程管理[每天或每月的某时执行某个任务],可以用timer和TimerTask来实现。

    本文会介绍如何实现一个日程的方法。这里会设计两个类,一个侦听类,用来定时执行任务[可执行多个任务].一个任务类,用来调用任务.以下是实现每天15:00执行一个任务.

    1.listener class

    package timer;

    import java.util.TimerTask;
    import java.util.Timer;
    import javax.servlet.*; 

    public class RemindListener implements ServletContextListener {
    private java.util.Timer timer = null;
    public void contextInitialized(ServletContextEvent sce) {
    timer = new java.util.Timer(true);
    sce.getServletContext().log(new java.util.Date()+"Timer start up!");
    timer.schedule(new RemindTask(),0,60*60*1000);//every 60 minute roll
    sce.getServletContext().log(new java.util.Date()+"Schedule loaded!");
    }
    public void contextDestroyed(ServletContextEvent sce) {
    timer.cancel();
    sce.getServletContext().log(new java.util.Date()+"Timer destroyed!");
    }

    }

    2.Task class
    package timer;

    import java.util.TimerTask;
    import java.util.Calendar;

    public class RemindTask extends TimerTask{
    private static final int C_SCHEDULE_HOUR   = 15;
    private static boolean isRunning = false;     
    public RemindTask() {

    }
    public void run() {
    Calendar cal = Calendar.getInstance();
             if (!isRunning)  {             
                 if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {   
                     isRunning = true;              
                     System.out.println(new java.util.Date()+"task start");   
                     //TODO for example
            int i = 0;
            while (i++ < 10) {
          System.out.println(new java.util.Date()+"Done!task" + i + "/" + 10);
           }
                     isRunning = false;              
                     System.out.println(new java.util.Date()+"All task Done!");              
                     }
            } 
             else 
                 {
                   System.out.println(new java.util.Date()+"Task existed!");
                 }
      }
    }

    3.loadonstart in web.xml
        <listener>
            <listener-class>timer.RemindListener</listener-class>
        </listener>

    4.restart server

    注意:当您为您的应用设置了虚拟机,定时器会启动两个.任务会执行两次!我的解决方法是为日程管理另起一个应用.

    //

    使用定时器,定时执行任务

    import java.util.Timer;

    import java.util.TimerTask;

    public class Test

    {

            public static void main(String args[])

            {

                    final Timer timer = new Timer();

                    timer.scheduleAtFixedRate(new TTask(),5000,1000);

            }

    }

    class TTask extends TimerTask

    {

            public void run()

            {

                    System.out.println("hello");

            }

    }

      在Java中实现Job Scheduling

     在大多数项目中,在特定的时间或频率下你需要完成一些特定的任务。在本文中我们将演示如何用标准的Java Timer API来实现。

    大多商业应用都会用报表和统计,很难想象没有这些帮助我们分析未来趋势的数据,我们还要这系统干什么。问题是如此多的数据我们该如何触发,如果处理对系统性能影响不大。比较好的方式是避开应用高峰,让服务器在闲暇时完成这些事。

    下面是我的程序:

    import java.util.TimerTask;

    import java.util.Calendar;

    import java.util.Date;

    import java.util.Timer;

     

    public class ReportGenerator extends TimerTask{

     

        /* (非 Javadoc)

         * @see java.util.TimerTask#run()

         */

        public void run() {

            System.out.println("Generating 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(),

          date.getTime(),

          1000 * 60 * 60 * 24 * 7

        );

      }

    }

    我先简单解释一下,在我们的例子中ReportGenerator继承java.util.TimerTask,它又继承了java.lang.Runnable,我们需要覆盖run()方法。

    调用时我们用schedule()方法让它每周日00分执行,避开服务器高峰,实现Job Scheduling的目的。

    总结

    以上是生活随笔为你收集整理的定时器 实现的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。