1 package org.feistymeow.process;
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
7 * A simple java thread that hearkens back to the HOOPLE C++ ethread in features.
9 * @author Chris Koeritz
10 * @copyright Copyright (c) 2010-$now By Feisty Meow Concerns Ltd.
11 * @license This file is free software; you can modify and redistribute it under the terms of the Apache License v2.0:
12 * http://www.apache.org/licenses/LICENSE-2.0
14 public abstract class ethread implements Runnable
16 private static Log c_logger = LogFactory.getLog(ethread.class);
18 // the actual java thread object.
19 private volatile Thread c_RealThread = null;
20 // provides synchronization for the thread.
21 private volatile Object c_lock = new Object();
22 // this is the timing period, for a timed thread. if zero, then this is a single shot thread.
23 private long c_period = 0;
24 // records whether the thread should shut down or not.
25 private boolean c_stopThread = false;
26 // snooze between checks on the stop timer.
27 final long SNOOZE_PERIOD = 20;
30 * creates a new single-shot ethread without starting it. this type of thread will run just once.
37 * creates a new periodic ethread without starting it. this type of thread runs every "period" milliseconds until stopped or until the
38 * performActivity method returns false.
40 public ethread(long period)
46 * this is the main function that derived classes must implement. it does the actual work that the thread is intended to perform. note
47 * that the derived version must not do anything to cause the thread to be ripped out while performActivity is still being invoked. the
48 * return value should be true if the thread can continue executing. this is meaningless for single shot threads executed via runOnce, but
49 * matters for the periodic threads started with runPeriodic.
51 abstract public boolean performActivity();
54 * Begins execution of the thread.
58 synchronized (c_lock) {
59 if (null == this.c_RealThread) {
60 this.c_RealThread = new Thread(this);
61 c_logger.debug("starting thread " + c_RealThread.getId());
62 this.c_RealThread.start();
68 * Stops execution of the thread, or at least attempts to.
77 } catch (InterruptedException e) {
78 // ignoring this since we'll keep snoozing as needed.
87 * Signals the thread to stop executing, but does not wait for it.
91 synchronized (c_lock) {
93 Thread goAway = c_RealThread;
102 * Returns true if the thread object is still alive. this does not necessarily mean it is currently active.
104 public boolean threadAlive()
106 synchronized (c_lock) {
107 return this.c_RealThread != null;
112 * returns true if the thread has been told to stop running.
114 public boolean shouldStop()
116 synchronized (c_lock) {
122 * this is the override from Runnable that allows us to call our own performActivity method. implementors should not override this; they
123 * should override performActivity instead.
128 if (!threadAlive()) {
129 return; // stopped before it ever started. how can this be? we just got invoked.
133 boolean keepGoing = performActivity();
135 c_logger.debug("thread returned false, signifying it wants to exit. now dropping it.");
139 // not a periodic thread, so we're done now.
142 long nextRun = System.currentTimeMillis() + c_period;
143 while (System.currentTimeMillis() < nextRun) {
148 Thread.sleep(SNOOZE_PERIOD);
149 } catch (InterruptedException e) {
150 // well, we'll hit it again soon.
154 } catch (Throwable t) {
155 c_logger.info("exception thrown from performActivity: " + t.getLocalizedMessage(), t);
157 // reset the thread held since we're leaving right now.