posts - 23,comments - 12,trackbacks - 0

在Windows编程中可以调用SetTimer在指定窗口安装定时器(Timer),定时器可以在指定的时间间隔周期性回调用户指定的方法,用来执行周期性的任务,如果想取消定时器,可以调用KillTimer取消。但是在java标准包里中并没有这种类。下面介绍的这个类包可以实现上述功能。

下面是接口,需要支持定时器功能的类要实现这个接口:

TimerClient.java

package com.ly.util;

/**
 * TimerClient Interface
 *
 * @version 1.0, 8 October 1995
 *
 */
public interface TimerClient
{
  void timerEvent(int id);
}

 

下面是定时器的实现,包括三个类:TimerCtl,TimerTask,TimerTasks。其中TimerTask用来描述定时器信息。TimerTasks是一个TimerTask的列表,这样我们就可以同时在一个应用中安插多个定时器。TimerCtl是定时器控制类,是个线程,不停地检查TimerTasks中是否有TimerTask到期,要是有TimerTask到达指定的时间,则回调TimerTask指定的TimerClient的timerEvent接口。

TimerCtl.java

package com.ly.util;

import java.util.Vector;
import java.util.Enumeration;
//import com.borland.jb.util.Diagnostic;

/**
 * Timer Component
 *
 * Note:
 *  - The successful operation of this timer requires clients to execute simple, short
 *    code snippets when called back by the engine.  Otherwise the queue's delivery
 *    mechanism will be held up
 *
 * Further work:
 *  - When Thread.Interrupt is implemented we can switch from the busy wait model to
 *    the calculated wait model.  Without the interrupt the thread waits for the
 *    calculated interval before waking up.  This is a problem if another shorter
 *    request arrives.  For now we'll assume the minimum resolution of the timer is
 *    100ms.
 *
 * @version 1.0, 2 October 1995
 *
 */
public class TimerCtl
{
  static TimerTasks timerTasks;

  public TimerCtl() {
  }

  /*
  * Start a timer running
  */
  public static void startTimer(TimerClient client, int eventId, long delay, boolean repeat) {
    // create the timer if necessary
    if (timerTasks == null) {
      timerTasks = new TimerTasks();
      timerTasks.start();
    }

    //Diagnostic.out.println("TIMER: startTimer"+eventId);

    // add the new task to the queue
    timerTasks.add(client, eventId, delay, repeat);
  }

  /*
  * Stop a timer
  */
  public static void stopTimer(TimerClient client, int eventId) {
    //Diagnostic.out.println("TIMER: stopTimer"+eventId);
    if(timerTasks != null)
        timerTasks.end(client, eventId);
  }
}

class TimerTasks extends Thread
{
  Vector tasks = new Vector();
  boolean suspended = false;
  boolean sleeping = false;

  /**
   * Thread task runner
   */
  public void run() {
    // Loop forever
    while (true) {
      long sleepTime = 0;

      // Ensure that the tasks class is protected
      synchronized (tasks) {
        //Diagnostic.out.println("TIMER: Tick");

        // Scan the job list for any jobs which may fire.
        // Mark one-shot jobs for deletion
        // Calculate the maximum time we can sleep for
        sleepTime = scan();

        // Delete DeletePending jobs.  DeletePending jobs result from one-shots which have
        // been sent, and repeat jobs which have been cancelled.  Jobs may have been
        // cancelled during the Scan process.
        purge();
      }

      // Suspend timer if necessary
      if (tasks.size() == 0) {
        //Diagnostic.out.println("TIMER: Suspend");
        try {
          synchronized(this) {
            suspended = true;
            wait();
          }
        }
        catch (InterruptedException e) {
        }
      }
      else {
        //Diagnostic.out.println("TIMER: Suggested Sleeping for "+sleepTime);
        if (sleepTime >= 0) {
          try {
            sleeping = true;
            sleep(sleepTime);
            sleeping = false;
          }
          catch (InterruptedException i) {
            //Diagnostic.out.println("TIMER: Caught me napping");
          }
        }
      }
    }
  }

  /**
   * Add a new task
   */
  public void add(TimerClient client, int eventId, long delay, boolean repeat) {
    TimerTask t = new TimerTask(client, eventId, delay, repeat);

    synchronized (tasks) {
      tasks.addElement((Object)t);
    }

    // Want instant response - wake the thread if it's napping
    // unfortunately the interrupt() method is not working
//    if (sleeping)
//      interrupt();

    if (suspended) {
      synchronized(this) {
        notify();
        //Diagnostic.out.println("TIMER: Resume");
        suspended = false;
      }
    }
  }

  /**
   * Find the job and mark it for deletion
   */
  public void end(TimerClient client, int eventId) {
    synchronized (tasks) {
      for (int i = 0; i < tasks.size(); i++) {
        TimerTask t = (TimerTask)tasks.elementAt(i);

        //if (!t.deletePending && t.client == client && t.eventId == eventId)
        if (t.deletePending == false && t.client == client && t.eventId == eventId) {
          // JPBS - if we don't reset 'repeat', deletePending will be set again
          t.repeat = false;
          t.deletePending = true;
          break;
        }
      }
    }
  }

  /**
   * Clear out all the dead wood
   */
  void purge() {
    for (int i = 0; i < tasks.size(); i++) {
      TimerTask t = (TimerTask)tasks.elementAt(i);

      if (t.deletePending) {
        //Diagnostic.out.println("TIMER: purged");

        tasks.removeElementAt(i);
        i--;
      }
    }
  }

  long scan() {
    // The value added to the current time determines the MAX time until
    // the next scan
    // This is 100 now since thread.interrupt() is not implemented
    long nextTime = System.currentTimeMillis() + 100;

    for (int i = 0; i < tasks.size(); i++) {
      TimerTask t = (TimerTask)tasks.elementAt(i);

      // if not already deletePending, test (and possibly send the event)
      // as a result, the job may be flagged for deletion.
      // May also be a non-repeating job and so require self deletion
      if (!t.deletePending)
        t.test();

      // if the task didn't get deleted - see what it contributes to the time
      if (!t.deletePending)
        nextTime = Math.min(nextTime, t.timeNext);

      //Diagnostic.out.println("TIMER: Scanning "+t.eventId+" "+(t.deletePending == true ? "DEL" : ""));
    }

    return nextTime - System.currentTimeMillis();
  }
}

class TimerTask
{
  TimerClient client;
  int         eventId;

  long        timePrev;
  long        timeDelay;
  long        timeNext;

  boolean repeat;
  boolean deletePending;

  public TimerTask(TimerClient client, int eventId, long timeDelay, boolean repeat) {
    this.client = client;
    this.eventId = eventId;
    this.timeDelay = timeDelay;
    this.repeat = repeat;

    // schedule the next click - now + delay
    timeNext = System.currentTimeMillis() + timeDelay;
    deletePending = false;

    //Diagnostic.out.println("TIMER: Adding New Task");
  }

  public void test() {
    if (System.currentTimeMillis() >= timeNext) {
      //Diagnostic.out.println("TIMER: fire");

      // Fire the event
      client.timerEvent(eventId);

      // Update the next time
      timeNext = System.currentTimeMillis() + timeDelay;

      deletePending = !repeat;
    }
  }
}

 

 
下面是一个使用例子

TimerTest.java

package com.ly.util;

import java.io.*;
import java.util.*;
import com.ly.util.*;

/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
public class TimerTest implements TimerClient{
public TimerTest()
{
starttime();
}
public void timerEvent(int id)
{
System.out.println("timerEvent...");
}
public void starttime()
{
TimerCtl.startTimer(this,1,5*1000,true);
}
public void stoptime()
{
TimerCtl.stopTimer(this,1);
}

public static void main(String[] args)
{
new TimerTest();
try
{
Thread.sleep(200000);
}catch(Exception e)
{
}

}
}

 

通过这种方式,可以高效地使用socket通讯,在异步socket版本没有发布以前,不失是一种解决问题的方法。:)

posted on 2005-07-26 09:00 my java 阅读(5812) 评论(1)  编辑  收藏 所属分类: java

FeedBack:
# re: java中定时器timer类的实现和源代码
2006-07-27 11:49 | supercai
在TimerTasks的run()中
try {
sleeping = true;
sleep(sleepTime);
sleeping = false;
}
catch (InterruptedException i) {
应该是
try {
sleeping = true;
sleep(sleepTime);
sleepTime=scan();
sleeping = false;
}
catch (InterruptedException i) {
才能正确执行

  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: