在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版本没有发布以前,不失是一种解决问题的方法。:)