001: /*
002: * @(#)LoopThread.java 0.9.0 06/02/2000 - 23:55:23
003: *
004: * Copyright (C) 2000,,2003 2002 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.util.thread.v1;
028:
029: /**
030: * For threads which loop endlessly (which is a common thing), this
031: * class implements the pause, start, and stop routines since JDK 1.2
032: * deprecated theirs.
033: * <p>
034: * This class delegates the Thread object, so that this class doesn't
035: * have to emulate all those thread methods. In this way, a LoopThread
036: * should act just like a Thread.
037: *
038: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
039: * @since June 4, 2000
040: * @version $Date: 2003/02/10 22:52:48 $
041: */
042: public class LoopThread {
043: public static final long MILLI_IN_SECOND = 1000;
044:
045: /* thread state: request a pause */
046: private boolean tryPause = false;
047:
048: /* thread state: request a stop */
049: private boolean tryStop = false;
050:
051: /* thread state: is it paused? */
052: private boolean isPaused = false;
053:
054: /* thread state: is it running? */
055: private boolean isRunning = false;
056:
057: /* wait/notify object for paused thread */
058: private Object pauseObject = new Object();
059:
060: /* delay time to sleep */
061: private long sleepTime = 6 * MILLI_IN_SECOND;
062:
063: /* Thread which runs in a loop */
064: private Thread this Thread;
065:
066: /* the runnable to be executed at each loop */
067: private Runnable runnable;
068:
069: /**
070: * The runnable class - keep it private so no one
071: * can directly access it in a thread but us.
072: */
073: private class LoopRunnable implements Runnable {
074: public void run() {
075: isRunning = true;
076: isPaused = false;
077: do {
078: // this slows things down, but we're
079: // a low priority anyway, so it doesn't really matter,
080: // besides, it makes the check more than safe.
081: synchronized (pauseObject) {
082: if (tryPause) {
083: isPaused = true;
084: try {
085: pauseObject.wait();
086: } catch (InterruptedException ie) {
087: // stop execution
088: tryStop = true;
089: }
090: isPaused = false;
091: // after pausing, we should check if we've been
092: // stopped.
093: continue;
094: }
095: }
096: // sleep
097:
098: if (sleepTime > 0 && !tryStop) {
099: //System.out.println("[Sleeping for "+sleepTime+" milliseconds]");
100: try {
101: Thread.sleep(sleepTime);
102: } catch (InterruptedException ie) {
103: }
104: }
105:
106: // Run the runnable
107: if (!tryStop) {
108: //System.out.println("[Running loop]");
109: runnable.run();
110: }
111: } while (!tryStop);
112: isRunning = false;
113: }
114: }
115:
116: /**
117: * Used in case the implementing class needs to postpone initialization
118: * until after the LoopThread construction.
119: */
120: public LoopThread() {
121: this .this Thread = new Thread(new LoopRunnable());
122: }
123:
124: /**
125: *
126: */
127: public LoopThread(Runnable loop) {
128: this .runnable = loop;
129: this .this Thread = new Thread(new LoopRunnable());
130: }
131:
132: /**
133: *
134: */
135: public LoopThread(Runnable loop, String threadName) {
136: this .runnable = loop;
137: this .this Thread = new Thread(new LoopRunnable());
138: }
139:
140: /**
141: *
142: */
143: public LoopThread(Runnable loop, ThreadGroup group) {
144: this .runnable = loop;
145: this .this Thread = new Thread(group, new LoopRunnable());
146: }
147:
148: /**
149: *
150: */
151: public LoopThread(Runnable loop, ThreadGroup group,
152: String threadName) {
153: this .runnable = loop;
154: this .this Thread = new Thread(group, new LoopRunnable(),
155: threadName);
156: }
157:
158: /**
159: * @see java.lang.Thread#getPriority()
160: */
161: public int getPriority() {
162: return this .this Thread.getPriority();
163: }
164:
165: /**
166: *
167: * @see java.lang.Thread#setPriority( int )
168: */
169: public void setPriority(int priority) {
170: this .this Thread.setPriority(priority);
171: }
172:
173: /**
174: *
175: * @see java.lang.Thread#getThreadGroup()
176: */
177: public ThreadGroup getThreadGroup() {
178: return this .this Thread.getThreadGroup();
179: }
180:
181: /**
182: *
183: * @see java.lang.Thread#isAlive()
184: */
185: public boolean isAlive() {
186: return this .this Thread.isAlive();
187: }
188:
189: /**
190: *
191: * @see java.lang.Thread#isDaemon()
192: */
193: public boolean isDaemon() {
194: return this .this Thread.isDaemon();
195: }
196:
197: /**
198: *
199: * @see java.lang.Thread#setDaemon( boolean )
200: */
201: public void setDaemon(boolean on) {
202: this .this Thread.setDaemon(on);
203: }
204:
205: /**
206: *
207: * @see java.lang.Thread#join()
208: */
209: public void join() throws InterruptedException {
210: if (this .isRunning) {
211: throw new InterruptedException(
212: "can't join - thread is running");
213: }
214: this .this Thread.join();
215: }
216:
217: /**
218: * Sets the runnable instance after construction. It cannot be
219: * changed once the thread is running.
220: */
221: public void setRunnable(Runnable run) {
222: if (this .isRunning) {
223: throw new IllegalStateException(
224: "can't change a running thread's " + "runnable");
225: }
226: this .runnable = run;
227: }
228:
229: /**
230: *
231: * @see java.lang.Thread#start()
232: */
233: public void start() {
234: if (this .isRunning) {
235: throw new IllegalStateException(
236: "can't start a running thread");
237: }
238: this .tryPause = false;
239: this .tryStop = false;
240: this .this Thread.start();
241: }
242:
243: /**
244: * A non-deprecated, nice-to-the-system, thread suspension method.
245: *
246: * @see java.lang.Thread#suspend()
247: */
248: public void suspend() {
249: if (this .tryStop || !this .isRunning) {
250: throw new IllegalStateException(
251: "Cannot pause a stopped thread");
252: }
253: this .tryPause = true;
254: }
255:
256: /**
257: *
258: * @see java.lang.Thread#resume()
259: */
260: public void resume() {
261: synchronized (this .pauseObject) {
262: if (!this .isPaused)
263: return;
264: this .tryPause = false;
265: this .pauseObject.notifyAll();
266: }
267: }
268:
269: /**
270: *
271: * @see java.lang.Thread#stop()
272: */
273: public void stop() {
274: if (!this .isRunning) {
275: return; // tried stopping a stopped thread!
276: }
277: this .tryStop = true;
278:
279: // In case the thread is paused, we should resume it to have it
280: // quit naturally.
281: resume();
282: }
283:
284: /**
285: *
286: */
287: public boolean isPaused() {
288: return this .isPaused;
289: }
290:
291: /**
292: *
293: */
294: public boolean isRunning() {
295: return this .isRunning;
296: }
297:
298: /**
299: * Retrieves the sleep time in seconds.
300: */
301: public int getSleepTime() {
302: return (int) (this .sleepTime / MILLI_IN_SECOND);
303: }
304:
305: /**
306: * Sets the sleep time in seconds.
307: */
308: public void setSleepTime(int seconds) {
309: this .sleepTime = seconds * MILLI_IN_SECOND;
310: }
311:
312: /**
313: * Sets the sleep time in milliseconds.
314: */
315: public void setSleepTimeMillis(long millis) {
316: this .sleepTime = millis;
317: }
318:
319: /**
320: * Retrieves the sleep time in milliseconds.
321: */
322: public long getSleepTimeMillis() {
323: return this .sleepTime;
324: }
325:
326: /**
327: *
328: * @see java.lang.Thread#toString()
329: */
330: public String toString() {
331: return this.thisThread.toString();
332: }
333: }
|