Mega Code Archive

 
Categories / Java / Development Class
 

A simple implementation of the Java 1 3 java util Timer API

/*  * Copyright (c) 2004 David Flanagan.  All rights reserved.  * This code is from the book Java Examples in a Nutshell, 3nd Edition.  * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.  * You may study, use, and modify it for any non-commercial purpose,  * including teaching and use in open-source projects.  * You may distribute it non-commercially as long as you retain this notice.  * For a commercial use license, or to purchase the book,   * please visit http://www.davidflanagan.com/javaexamples3.  */ import java.util.Comparator; import java.util.Date; import java.util.SortedSet; import java.util.TreeSet; abstract class TimerTask implements Runnable {   boolean cancelled = false; // Has it been cancelled?   long nextTime = -1; // When is it next scheduled?   long period; // What is the execution interval   boolean fixedRate; // Fixed-rate execution?   protected TimerTask() {   }   /**    * Cancel the execution of the task. Return true if it was actually running,    * or false if it was already cancelled or never scheduled.    */   public boolean cancel() {     if (cancelled)       return false; // Already cancelled;     cancelled = true; // Cancel it     if (nextTime == -1)       return false; // Never scheduled;     return true;   }   /**    * When it the timer scheduled to execute? The run() method can use this to    * see whether it was invoked when it was supposed to be    */   public long scheduledExecutionTime() {     return nextTime;   }   /**    * Subclasses must override this to provide that code that is to be run. The    * Timer class will invoke this from its internal thread.    */   public abstract void run();   // This method is used by Timer to tell the Task how it is scheduled.   void schedule(long nextTime, long period, boolean fixedRate) {     this.nextTime = nextTime;     this.period = period;     this.fixedRate = fixedRate;   }   // This will be called by Timer after Timer calls the run method.   boolean reschedule() {     if (period == 0 || cancelled)       return false; // Don't run it again     if (fixedRate)       nextTime += period;     else       nextTime = System.currentTimeMillis() + period;     return true;   } } /**  * This class is a simple implementation of the Java 1.3 java.util.Timer API  */ public class Timer {   // This sorted set stores the tasks that this Timer is responsible for.   // It uses a comparator to sort the tasks by scheduled execution time.   SortedSet tasks = new TreeSet(new Comparator() {     public int compare(Object a, Object b) {       return (int) (((TimerTask) a).nextTime - ((TimerTask) b).nextTime);     }     public boolean equals(Object o) {       return this == o;     }   });   // This is the thread the timer uses to execute the tasks.   // The TimerThread class is defined below.   TimerThread timer;   /** This constructor create a Timer that does not use a daemon thread */   public Timer() {     this(false);   }   /** The main constructor: the internal thread is a daemon if specified */   public Timer(boolean isDaemon) {     timer = new TimerThread(isDaemon); // TimerThread is defined below     timer.start(); // Start the thread running   }   /** Stop the timer thread, and discard all scheduled tasks */   public void cancel() {     synchronized (tasks) { // Only one thread at a time!       timer.pleaseStop(); // Set a flag asking the thread to stop       tasks.clear(); // Discard all tasks       tasks.notify(); // Wake up the thread if it is in wait().     }   }   /** Schedule a single execution after delay milliseconds */   public void schedule(TimerTask task, long delay) {     task.schedule(System.currentTimeMillis() + delay, 0, false);     schedule(task);   }   /** Schedule a single execution at the specified time */   public void schedule(TimerTask task, Date time) {     task.schedule(time.getTime(), 0, false);     schedule(task);   }   /** Schedule a periodic execution starting at the specified time */   public void schedule(TimerTask task, Date firstTime, long period) {     task.schedule(firstTime.getTime(), period, false);     schedule(task);   }   /** Schedule a periodic execution starting after the specified delay */   public void schedule(TimerTask task, long delay, long period) {     task.schedule(System.currentTimeMillis() + delay, period, false);     schedule(task);   }   /**    * Schedule a periodic execution starting after the specified delay. Schedule    * fixed-rate executions period ms after the start of the last. Instead of    * fixed-interval executions measured from the end of the last.    */   public void scheduleAtFixedRate(TimerTask task, long delay, long period) {     task.schedule(System.currentTimeMillis() + delay, period, true);     schedule(task);   }   /** Schedule a periodic execution starting after the specified time */   public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {     task.schedule(firstTime.getTime(), period, true);     schedule(task);   }   // This internal method adds a task to the sorted set of tasks   void schedule(TimerTask task) {     synchronized (tasks) { // Only one thread can modify tasks at a time!       tasks.add(task); // Add the task to the sorted set of tasks       tasks.notify(); // Wake up the thread if it is waiting     }   }   /**    * This inner class defines the thread that runs each of the tasks at their    * scheduled times    */   class TimerThread extends Thread {     // This flag is will be set true to tell the thread to stop running.     // Note that it is declared volatile, which means that it may be     // changed asynchronously by another thread, so threads must always     // read its current value, and not used a cached version.     volatile boolean stopped = false;     // The constructor     TimerThread(boolean isDaemon) {       setDaemon(isDaemon);     }     // Ask the thread to stop by setting the flag above     void pleaseStop() {       stopped = true;     }     // This is the body of the thread     public void run() {       TimerTask readyToRun = null; // Is there a task to run right now?       // The thread loops until the stopped flag is set to true.       while (!stopped) {         // If there is a task that is ready to run, then run it!         if (readyToRun != null) {           if (readyToRun.cancelled) { // If it was cancelled, skip.             readyToRun = null;             continue;           }           // Run the task.           readyToRun.run();           // Ask it to reschedule itself, and if it wants to run           // again, then insert it back into the set of tasks.           if (readyToRun.reschedule())             schedule(readyToRun);           // We've run it, so there is nothing to run now           readyToRun = null;           // Go back to top of the loop to see if we've been stopped           continue;         }         // Now acquire a lock on the set of tasks         synchronized (tasks) {           long timeout; // how many ms 'till the next execution?           if (tasks.isEmpty()) { // If there aren't any tasks             timeout = 0; // Wait 'till notified of a new task           } else {             // If there are scheduled tasks, then get the first one             // Since the set is sorted, this is the next one.             TimerTask t = (TimerTask) tasks.first();             // How long 'till it is next run?             timeout = t.nextTime - System.currentTimeMillis();             // Check whether it needs to run now             if (timeout <= 0) {               readyToRun = t; // Save it as ready to run               tasks.remove(t); // Remove it from the set               // Break out of the synchronized section before               // we run the task               continue;             }           }           // If we get here, there is nothing ready to run now,           // so wait for time to run out, or wait 'till notify() is           // called when something new is added to the set of tasks.           try {             tasks.wait(timeout);           } catch (InterruptedException e) {           }           // When we wake up, go back up to the top of the while loop         }       }     }   }   /** This inner class defines a test program */   public static class Test {     public static void main(String[] args) {       final TimerTask t1 = new TimerTask() { // Task 1: print "boom"         public void run() {           System.out.println("boom");         }       };       final TimerTask t2 = new TimerTask() { // Task 2: print "BOOM"         public void run() {           System.out.println("\tBOOM");         }       };       final TimerTask t3 = new TimerTask() { // Task 3: cancel the tasks         public void run() {           t1.cancel();           t2.cancel();         }       };       // Create a timer, and schedule some tasks       final Timer timer = new Timer();       timer.schedule(t1, 0, 500); // boom every .5sec starting now       timer.schedule(t2, 2000, 2000); // BOOM every 2s, starting in 2s       timer.schedule(t3, 5000); // Stop them after 5 seconds       // Schedule a final task: starting in 5 seconds, count       // down from 5, then destroy the timer, which, since it is       // the only remaining thread, will cause the program to exit.       timer.scheduleAtFixedRate(new TimerTask() {         public int times = 5;         public void run() {           System.out.println(times--);           if (times == 0)             timer.cancel();         }       }, 5000, 500);     }   } }