// Copyright (c) 2003 Dustin Sallings <dustin@spy.net> package net.spy.util; import net.spy.SpyThread; /** * A Thread that loops over a runLoop(). */ public abstract class LoopingThread extends SpyThread { /** * Default number of milliseconds to spend on each loop. */ public static final int DEFAULT_MS_PER_LOOP=5000; private volatile boolean keepGoing=true; private int msPerLoop=DEFAULT_MS_PER_LOOP; /** * Get an instance of LoopingThread. */ protected LoopingThread() { super(); } /** * Get a LoopingThread with a specified name. */ protected LoopingThread(String name) { super(name); } /** * Get a looping thread belonging to a specific group and having the * specified name. */ protected LoopingThread(ThreadGroup tg, String name) { super(tg, name); } /** * Set the number of milliseconds to sleep during each loop. * * Default is 5000 (five seconds). * * @param to number of milliseconds to delay between loops */ public void setMsPerLoop(int to) { this.msPerLoop = to; } /** * Get the number of milliseconds to sleep during each loop. * * @return the number of milliseconds to wait during a loop. */ public int getMsPerLoop() { return(msPerLoop); } /** * Request the looping should end. */ public synchronized void requestStop() { // notify so the wait will finish keepGoing=false; notifyAll(); } /** * This is the stuff that should happen during each execution of the * run loop. */ protected abstract void runLoop(); /** * Method to pause between loops. * * This is implemented via wait() so a notify() will cause this object * to awaken from its sleep. */ protected void performDelay() { try { synchronized(this) { wait(getMsPerLoop()); } } catch(InterruptedException e) { delayInterrupted(e); } } /** * This method is invoked when the delay is interrupted. * * @param e the interrupted exception */ protected void delayInterrupted(InterruptedException e) { getLogger().warn("Somebody interrupted my sleep", e); } /** * The run loop itself. */ @Override public void run() { startingUp(); while(keepGoing) { // Normally, we'd want to delay before the run loop, but here // it doesn't so much matter because there's no exception // handling to cause us to hop over the delay. If the runLoop // throws a RuntimeException, we leave the loop. runLoop(); performDelay(); } getLogger().info("Thread finishing."); shuttingDown(); } /** * Hook method invoked when the thread is starting up. */ protected void startingUp() { // hook goes here } /** * Hook method invoked when the thread is shutting down. */ protected void shuttingDown() { // hook goes here } }