package rescuecore2.misc; /** Abstract class for threads that need to repeat a unit of work, for example listening on a socket and dispatching data to listeners. */ public abstract class WorkerThread extends Thread { private volatile boolean running; private volatile boolean killed; /** Construct a worker thread. */ public WorkerThread() { running = true; killed = false; } /** Interrupt any current work, tell the thread to stop and wait for the thread to die. @throws InterruptedException If the thread that called kill is itself interrupted. */ public void kill() throws InterruptedException { synchronized (this) { if (killed) { return; } killed = true; } if (Thread.currentThread() == this) { // This thread is killing itself. Just return - the run loop will terminate now that "killed" is true. return; } // Interrupt the worker thread this.interrupt(); // Maybe the calling thread is already interrupted if (Thread.interrupted()) { throw new InterruptedException(); } this.join(); } @Override public void run() { setup(); try { while (isRunning()) { try { running = work(); } catch (InterruptedException e) { running = false; } } } finally { cleanup(); } } /** Find out if this thread is still running. If {@link #kill} has been called (and returned) or if {@link #work} has returned false then this worker thread is not still running. @return True if it is still running and has not been killed, false otherwise. */ public boolean isRunning() { synchronized (this) { return !killed && running; } } /** Do a unit of work and return whether there is more work to be done. Implementations should check periodically for interruptions and throw an exception when required. @return True if more work remains, false otherwise. @throws InterruptedException If the worker thread is interrupted. */ protected abstract boolean work() throws InterruptedException; /** Perform any setup necessary before work begins. Default implementation does nothing. */ protected void setup() {} /** Perform any cleanup necessary after work finishes. This will be called even if the {@link #work} method throws an exception. It is highly recommended that this method does not throw any exceptions. Default implementation does nothing. */ protected void cleanup() {} }