Class ClockDaemon


  • public class ClockDaemon
    extends ThreadFactoryUser
    A general-purpose time-based daemon, vaguely similar in functionality to common system-level utilities such as at (and the associated crond) in Unix. Objects of this class maintain a single thread and a task queue that may be used to execute Runnable commands in any of three modes -- absolute (run at a given time), relative (run after a given delay), and periodic (cyclically run with a given delay).

    All commands are executed by the single background thread. The thread is not actually started until the first request is encountered. Also, if the thread is stopped for any reason, one is started upon encountering the next request, or restart() is invoked.

    If you would instead like commands run in their own threads, you can use as arguments Runnable commands that start their own threads (or perhaps wrap within ThreadedExecutors).

    You can also use multiple daemon objects, each using a different background thread. However, one of the reasons for using a time daemon is to pool together processing of infrequent tasks using a single background thread.

    Background threads are created using a ThreadFactory. The default factory does not automatically setDaemon status.

    The class uses Java timed waits for scheduling. These can vary in precision across platforms, and provide no real-time guarantees about meeting deadlines.

    [ Introduction to this package. ]

    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      protected class  ClockDaemon.RunLoop
      The runloop is isolated in its own Runnable class just so that the main class need not implement Runnable, which would allow others to directly invoke run, which is not supported.
      protected static class  ClockDaemon.TaskNode  
    • Constructor Summary

      Constructors 
      Constructor Description
      ClockDaemon()
      Create a new ClockDaemon
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static void cancel​(java.lang.Object taskID)
      Cancel a scheduled task that has not yet been run.
      protected void clearThread()
      set thread_ to null to indicate termination
      java.lang.Object executeAfterDelay​(long millisecondsToDelay, java.lang.Runnable command)
      Excecute the given command after waiting for the given delay.
      java.lang.Object executeAt​(java.util.Date date, java.lang.Runnable command)
      Execute the given command at the given time.
      java.lang.Object executePeriodically​(long period, java.lang.Runnable command, boolean startNow)
      Execute the given command every period milliseconds.
      java.lang.Thread getThread()
      Return the thread being used to process commands, or null if there is no such thread.
      protected ClockDaemon.TaskNode nextTask()
      Return the next task to execute, or null if thread is interrupted
      void restart()
      Start (or restart) a thread to process commands, or wake up an existing thread if one is already running.
      void shutDown()
      Cancel all tasks and interrupt the background thread executing the current task, if any.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • heap_

        protected final Heap heap_
        tasks are maintained in a standard priority queue
      • thread_

        protected java.lang.Thread thread_
        The thread used to process commands
    • Constructor Detail

      • ClockDaemon

        public ClockDaemon()
        Create a new ClockDaemon
    • Method Detail

      • executeAt

        public java.lang.Object executeAt​(java.util.Date date,
                                          java.lang.Runnable command)
        Execute the given command at the given time.
        Parameters:
        date - -- the absolute time to run the command, expressed as a java.util.Date.
        command - -- the command to run at the given time.
        Returns:
        taskID -- an opaque reference that can be used to cancel execution request
      • executeAfterDelay

        public java.lang.Object executeAfterDelay​(long millisecondsToDelay,
                                                  java.lang.Runnable command)
        Excecute the given command after waiting for the given delay.

        Sample Usage. You can use a ClockDaemon to arrange timeout callbacks to break out of stuck IO. For example (code sketch):

         class X {   ...
         
           ClockDaemon timer = ...
           Thread readerThread;
           FileInputStream datafile;
         
           void startReadThread() {
             datafile = new FileInputStream("data", ...);
         
             readerThread = new Thread(new Runnable() {
              public void run() {
                for(;;) {
                  // try to gracefully exit before blocking
                 if (Thread.currentThread().isInterrupted()) {
                   quietlyWrapUpAndReturn();
                 }
                 else {
                   try {
                     int c = datafile.read();
                     if (c == -1) break;
                     else process(c);
                   }
                   catch (IOException ex) {
                    cleanup();
                    return;
                  }
               }
             } };
        
            readerThread.start();
        
            // establish callback to cancel after 60 seconds
            timer.executeAfterDelay(60000, new Runnable() {
              readerThread.interrupt();    // try to interrupt thread
              datafile.close(); // force thread to lose its input file 
            });
           } 
         }
         
        Parameters:
        millisecondsToDelay - -- the number of milliseconds from now to run the command.
        command - -- the command to run after the delay.
        Returns:
        taskID -- an opaque reference that can be used to cancel execution request
      • executePeriodically

        public java.lang.Object executePeriodically​(long period,
                                                    java.lang.Runnable command,
                                                    boolean startNow)
        Execute the given command every period milliseconds. If startNow is true, execution begins immediately, otherwise, it begins after the first period delay.

        Sample Usage. Here is one way to update Swing components acting as progress indicators for long-running actions.

         class X {
           JLabel statusLabel = ...;
        
           int percentComplete = 0;
           synchronized int  getPercentComplete() { return percentComplete; }
           synchronized void setPercentComplete(int p) { percentComplete = p; }
        
           ClockDaemon cd = ...;
         
           void startWorking() {
             Runnable showPct = new Runnable() {
               public void run() {
                  SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                      statusLabel.setText(getPercentComplete() + "%");
                    } 
                  } 
               } 
             };
        
             final Object updater = cd.executePeriodically(500, showPct, true);
        
             Runnable action = new Runnable() {
               public void run() {
                 for (int i = 0; i < 100; ++i) {
                   work();
                   setPercentComplete(i);
                 }
                 cd.cancel(updater);
               }
             };
        
             new Thread(action).start();
           }
         }  
         
        Parameters:
        period - -- the period, in milliseconds. Periods are measured from start-of-task to the next start-of-task. It is generally a bad idea to use a period that is shorter than the expected task duration.
        command - -- the command to run at each cycle
        startNow - -- true if the cycle should start with execution of the task now. Otherwise, the cycle starts with a delay of period milliseconds.
        Returns:
        taskID -- an opaque reference that can be used to cancel execution request
        Throws:
        java.lang.IllegalArgumentException - if period less than or equal to zero.
      • cancel

        public static void cancel​(java.lang.Object taskID)
        Cancel a scheduled task that has not yet been run. The task will be cancelled upon the next opportunity to run it. This has no effect if this is a one-shot task that has already executed. Also, if an execution is in progress, it will complete normally. (It may however be interrupted via getThread().interrupt()). But if it is a periodic task, future iterations are cancelled.
        Parameters:
        taskID - -- a task reference returned by one of the execute commands
        Throws:
        java.lang.ClassCastException - if the taskID argument is not of the type returned by an execute command.
      • getThread

        public java.lang.Thread getThread()
        Return the thread being used to process commands, or null if there is no such thread. You can use this to invoke any special methods on the thread, for example, to interrupt it.
      • clearThread

        protected void clearThread()
        set thread_ to null to indicate termination
      • restart

        public void restart()
        Start (or restart) a thread to process commands, or wake up an existing thread if one is already running. This method can be invoked if the background thread crashed due to an unrecoverable exception in an executed command.
      • shutDown

        public void shutDown()
        Cancel all tasks and interrupt the background thread executing the current task, if any. A new background thread will be started if new execution requests are encountered. If the currently executing task does not repsond to interrupts, the current thread may persist, even if a new thread is started via restart().
      • nextTask

        protected ClockDaemon.TaskNode nextTask()
        Return the next task to execute, or null if thread is interrupted