001 /*
002 * $Id: AnimatorThread.java,v 1.5 2003/09/23 15:31:11 gus Exp $
003 *
004 * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's AP Group.
005 * For more information, see <a href="http://www.ai.mit.edu/projects/cs101/">the
006 * CS101 homepage</a> or email <las@ai.mit.edu>.
007 *
008 * Copyright (C) 1999 Massachusetts Institute of Technology.
009 * Please do not redistribute without obtaining permission.
010 */
011
012 package cs101.lang;
013
014 /**
015 * This class replaces Thread as a way to animate autonomous objects.
016 * An AnimatorThread can be passed any object that implements the
017 * Animate interface. The AnimatorThread (when started) begins
018 * executing at the Animate's act() method.
019 *
020 * Instances of this class provide safe ways to start, stop, suspend,
021 * and resume execution through the use of startExecution(),
022 * stopExecution(), suspendExecution() and resumeExecution() methods.
023 *
024 * Unlike java.lang.Thread, this class cannot be extended.
025 *
026 * Copyright 1999 Massachusetts Institute of Technology
027 *
028 * @see Thread
029 * @see cs101.lang.Animate
030 * @see #startExecution()
031 * @see #stopExecution()
032 * @see #suspendExecution()
033 * @see #resumeExecution()
034 *
035 * @author Lynn Andrea Stein, las@ai.mit.edu
036 * @version $Id: AnimatorThread.java,v 1.5 2003/09/23 15:31:11 gus Exp $
037 *
038 */
039 public final class AnimatorThread extends Thread
040 {
041 /* CONSTANTS */
042
043 /**
044 * These constants allow mnemonic access to AnimateObject's final
045 * constructor argument, i.e., should the object start running on
046 * construction or on (a subsequent) call to a separate start()
047 * method?
048 *
049 * @see #AnimatorThread( Animate, boolean )
050 */
051 public static final boolean START_IMMEDIATELY = true,
052 DONT_START_YET = false;
053
054 /**
055 * Default values for sleepMinInterval, sleepRange. Static so
056 * they're available to constructors.
057 *
058 * These default values are chosen to allow GUI events to be
059 * easily perceived.
060 *
061 */
062 private static final long DEFAULT_SLEEP_MIN_INTERVAL = 200,
063 DEFAULT_SLEEP_RANGE = 400;
064
065 /* FIELDS */
066
067 /**
068 * These private fields control the state of execution of this
069 * object's animacy. They supercede the now-deprecated
070 * Thread.stop()/Thread.suspend() regime of Java 1.0. <p>
071 *
072 * Note that they must be volatile in order to ensure correct
073 * access by the animating Thread.
074 *
075 * @see #stopExecution()
076 * @see #suspendExecution()
077 * @see #resumeExecution()
078 */
079 private volatile boolean isStopped = false,
080 isSuspended = false;
081 /**
082 * This object exists only to be a unique privately held object
083 * on which wait() and notify() can be invoked in cases of ersatz
084 * suspension. This is a part of the solution to handle the
085 * now-deprecated Thread.suspend() regime of Java 1.0. <p>
086 *
087 * @see #stopExecution()
088 * @see #suspendExecution()
089 * @see #resumeExecution()
090 */
091 private final Object suspendLock = new Object();
092 /**
093 * These values control the sleep interval between calls to the
094 * Animate's act() method: the smallest interval for which this
095 * AnimatorThread will sleep and the variance above this interval.
096 * In no case will the minimum sleep time be less than
097 * this.sleepMinInterval; it could be as long as
098 * this.sleepMinInterval + this.sleepRange.
099 *
100 * The default values are set by
101 * AnimatorThread.DEFAULT_SLEEP_MIN_INTERVAL and
102 * AnimatorThread.DEFAULT_SLEEP_RANGE. These values can be
103 * overriden either by the constructor or by means of a public
104 * setter method.
105 *
106 * @see #AnimatorThread( Animate, long, long )
107 * @see #setSleepMinInterval(long)
108 * @see #setSleepRange( long )
109 * @see #DEFAULT_SLEEP_MIN_INTERVAL
110 * @see #DEFAULT_SLEEP_RANGE
111 */
112 private long sleepMinInterval,
113 sleepRange;
114
115 /**
116 * This is the object that this AnimatorThread will Animate.
117 *
118 * @see Animate
119 */
120 private final Animate what;
121
122
123 /* CONSTRUCTORS */
124
125 /**
126 * This constructor requires the Animate that is to be animated.
127 * Once the AnimatorThread being constructed is started (using its
128 * start() method), the Animate's act() method will be called
129 * periodically, with the interval between calls controlled by
130 * sleepMinInterval and sleepRange.
131 *
132 * @param a the Animate to be animated.
133 *
134 * @see Animate
135 * @see #start()
136 * @see #setSleepMinInterval(long)
137 * @see #setSleepRange( long )
138 */
139 public AnimatorThread ( Animate a )
140 {
141 this( a, AnimatorThread.DONT_START_YET );
142 }
143
144 /**
145 * This constructor requires the Animate that is to be animated and
146 * a boolean value (expected to be one of
147 * AnimatorThread.START_IMMEDIATELY or
148 * AnimatorThread.DONT_START_YET) that determines whether this
149 * AnimatorThread should start running as the last step of its
150 * construction. If this boolean's value is START_IMMEDIATELY,
151 * execution will begin as soon as this constructor exits.
152 * Otherwise, a subsequent call to the AnimatorThread's start()
153 * method is required.
154 *
155 * It is expected that this boolean will generally be
156 * AnimatorThread.START_IMMEDIATELY as the default value of the
157 * one-arg constructor is AnimatorThread.DONT_START_YET.
158 *
159 * @param a the Animate to be animated.
160 * @param startImmediately one of AnimatorThread.START_IMMEDIATELY
161 * or AnimatorThread.DONT_START_YET
162 *
163 * @see Animate
164 * @see #AnimatorThread( Animate )
165 * @see #start()
166 * @see #setSleepMinInterval(long)
167 * @see #setSleepRange( long )
168 */
169 public AnimatorThread ( Animate a, boolean startImmediately )
170 {
171 this( a, startImmediately,
172 AnimatorThread.DEFAULT_SLEEP_MIN_INTERVAL,
173 AnimatorThread.DEFAULT_SLEEP_RANGE );
174 }
175
176 /**
177 * This constructor requires the Animate that is to be animated and
178 * a long representing the desired variance in sleep times between
179 * calls to the Animate's act() method. This constructor requires
180 * an additional call to the AnimatorThread's start() method.
181 *
182 * The sleep time between calls to the Animate's act() will vary
183 * between this.sleepMinInterval and this.sleepMinInterval +
184 * sleepRange.
185 *
186 * @param a the Animate to be animated.
187 * @param sleepRange the desired variance in sleep times above and
188 * beyond sleepMinInterval
189 *
190 * @see Animate
191 * @see #AnimatorThread( Animate )
192 * @see #start()
193 * @see #setSleepMinInterval(long)
194 * @see #setSleepRange( long )
195 */
196 public AnimatorThread ( Animate a, long sleepRange )
197 {
198 this( a, AnimatorThread.DONT_START_YET, sleepRange );
199 }
200
201 /**
202 * This constructor requires the Animate that is to be animated, a
203 * boolean reflecting whether execution should begin immediately,
204 * and a long representing the desired variance in sleep times
205 * between calls to the Animate's act() method.
206 *
207 * @param a the Animate to be animated.
208 * @param startImmediately one of AnimatorThread.START_IMMEDIATELY
209 * or AnimatorThread.DONT_START_YET
210 * @param sleepRange the desired variance in sleep times above and
211 * beyond sleepMinInterval
212 *
213 * @see Animate
214 * @see #AnimatorThread( Animate, boolean )
215 * @see #AnimatorThread( Animate, long )
216 * @see #start()
217 * @see #setSleepMinInterval(long)
218 * @see #setSleepRange( long )
219 */
220 public AnimatorThread ( Animate a,
221 boolean startImmediately,
222 long sleepRange )
223 {
224 this( a, startImmediately, sleepRange,
225 AnimatorThread.DEFAULT_SLEEP_RANGE );
226 }
227
228 /**
229 * This constructor requires the Animate that is to be animated and
230 * two longs representing the desired variance in sleep times and
231 * the desired minimum sleep interval between calls to the Animate's
232 * act() method. This constructor requires an additional call to
233 * the AnimatorThread's start() method.
234 *
235 * The sleep time between calls to the Animate's act() will vary
236 * between sleepMinInterval and sleepMinInterval + sleepRange.
237 *
238 * @param a the Animate to be animated.
239 * @param sleepRange the desired variance in sleep times above and
240 * beyond sleepMinInterval
241 * @param sleepMinInterval the minimum interval between calls to
242 * the Animate's act() method
243 *
244 * @see Animate
245 * @see #AnimatorThread( Animate )
246 * @see #start()
247 * @see #setSleepMinInterval(long)
248 * @see #setSleepRange( long )
249 */
250 public AnimatorThread ( Animate a,
251 long sleepRange,
252 long sleepMinInterval )
253 {
254 this( a, AnimatorThread.DONT_START_YET, sleepRange, sleepMinInterval );
255 }
256
257 /**
258 * This constructor requires the Animate that is to be animated, a
259 * boolean reflecting whether execution should begin immediately,
260 * and two longs representing the desired variance in sleep times
261 * and the desired minimum sleep interval between calls to the
262 * Animate's act() method.
263 *
264 * @param a the Animate to be animated.
265 * @param startImmediately one of AnimatorThread.START_IMMEDIATELY
266 * or AnimatorThread.DONT_START_YET
267 * @param sleepRange the desired variance in sleep times above and
268 * beyond sleepMinInterval
269 * @param sleepMinInterval the minimum interval between calls to
270 * the Animate's act() method
271 *
272 * @see Animate
273 * @see #AnimatorThread( Animate, boolean )
274 * @see #AnimatorThread( Animate, long, long )
275 * @see #start()
276 * @see #setSleepMinInterval(long)
277 * @see #setSleepRange( long )
278 */
279 public AnimatorThread ( Animate a,
280 boolean startImmediately,
281 long sleepRange,
282 long sleepMinInterval )
283 {
284 super();
285 this.what = a;
286 if ( this.what == null )
287 {
288 throw new IllegalArgumentException("Cannot start an AnimatorThread "
289 + "without supplying an Animate!");
290 }
291 this.sleepRange = sleepRange;
292 this.sleepMinInterval = sleepMinInterval;
293 if ( startImmediately )
294 {
295 this.start();
296 }
297 }
298
299 /**
300
301 * Repeatedly invoke your Animate's act() method, sleeping between
302 * invocations.
303 *
304 * This method contains an amazing amount of hair to deal with
305 * suspension, resumption, and stopping of AnimatorThreads. See <a
306 * href="http://java.sun.com/products/jdk/1.2/docs/guide/misc/threadPrimitiveDeprecation.html">
307 * theJavaSoft statement on Thread primitive deprication. </a>
308 *
309 * @see Animate
310 * @see #setSleepMinInterval(long)
311 * @see #setSleepRange( long )
312 */
313 public void run()
314 {
315 RUN_LOOP:
316 while ( ! this.isStopped )
317 {
318 if ( this.isSuspended )
319 {
320 synchronized ( this.suspendLock )
321 {
322 while ( this.isSuspended )
323 {
324 try
325 {
326 this.suspendLock.wait();
327 }
328 catch ( InterruptedException e )
329 {
330 }
331 finally
332 {
333 if ( this.isStopped )
334 {
335 break RUN_LOOP;
336 }
337 }
338 }
339 }
340 }
341 try
342 {
343 Thread.sleep( Math.round( Math.random() * this.sleepRange )
344 + this.sleepMinInterval );
345 this.what.act();
346 }
347 catch ( InterruptedException e )
348 {
349 }
350 }
351 }
352
353 /**
354 * Begin execution. This causes the AnimatorThread to periodically
355 * call its Animate's act() method. (Same as this.startExecution().)
356 *
357 * @see Animate
358 * @see #AnimatorThread(Animate)
359 * @see Thread#start()
360 */
361 public void start()
362 {
363 this.startExecution();
364 }
365
366 /**
367 * Begin execution. This causes the AnimatorThread to periodically
368 * call its Animate's act() method.
369 *
370 * @see Animate
371 * @see #AnimatorThread(Animate)
372 * @see Thread#start()
373 */
374 public void startExecution()
375 {
376 if (( ! this.isStopped ) && ( ! this.isAlive() ))
377 {
378 super.start();
379 }
380 }
381
382 /**
383 * Terminates execution. This causes the AnimatorThread to cease
384 * execution immediately. Once stopped, an AnimatorThread cannot
385 * be restarted.
386 *
387 * Safely replaces Thread's (deprecated) stop() method.
388 *
389 * @see Thread#stop()
390 */
391 public void stopExecution()
392 {
393 this.isStopped = true; // Set state
394 this.interrupt(); // Wake if sleeping, waiting, etc.
395 }
396
397 /**
398 * Temporarily suspends execution. This causes the AnimatorThread
399 * to suspend execution following the next act() of its Animate.
400 * Periodic execution of the Animate's act() method can be restarted
401 * using resumeExecution().
402 *
403 * Safely replaces Thread's (deprecated) suspend() method.
404 *
405 * @see #resumeExecution()
406 * @see Thread#suspend()
407 *
408 */
409 public void suspendExecution()
410 {
411 synchronized ( this.suspendLock ) // I suspect this
412 { // synchronization is
413 this.isSuspended = true; // unnecessary....
414 }
415 }
416
417 /**
418 * Resumes execution after a temporary suspension (using
419 * suspendExecution()).
420 *
421 * Safely replaces Thread's (deprecated) resume() method.
422 *
423 * @see #suspendExecution()
424 * @see Thread#resume()
425 *
426 */
427 public void resumeExecution()
428 {
429 synchronized ( this.suspendLock )
430 {
431 this.isSuspended = false;
432 this.suspendLock.notify();
433 }
434 }
435
436 /**
437 * Gives access to this AnimatorThread's sleep minimum.
438 * This controls the smallest interval for which this AnimatorThread
439 * will sleep, i.e., the minimum time between actions for the
440 * Animate that it animates.
441 *
442 * If sleepMinInterval is set to 0, it is possible that this
443 * AnimatorThread will prevent execution by other Threads by fully
444 * occupying the CPU.
445 *
446 * @see #AnimatorThread( Animate, boolean, long, long )
447 * @see #setSleepRange( long )
448 */
449 public void setSleepMinInterval( long minInterval )
450 {
451 this.sleepMinInterval = minInterval;
452 }
453
454 /**
455 * This controls the possible range of durations for AnimatorThread
456 * to sleep, i.e., the possible time between actions for the Animate
457 * that it animates. In no case will the minimum sleep time be less
458 * than this.sleepMinInterval; it could be as long as
459 * this.sleepMinInterval + this.sleepRange.
460 *
461 * Gives access to this AnimatorThread's sleep variance. If 0, this
462 * AnimatorThread will sleep for the same amount of time between each
463 * invocation of the Animate's act() method.
464 *
465 * @see #AnimatorThread( Animate, boolean, long, long )
466 * @see #setSleepRange( long )
467 */
468 public void setSleepRange( long range )
469 {
470 this.sleepRange = range;
471 }
472
473 }
474
475 /*
476 * $Log: AnimatorThread.java,v $
477 * Revision 1.5 2003/09/23 15:31:11 gus
478 * more javadoc fixes
479 *
480 * Revision 1.4 2003/09/23 15:02:58 gus
481 * Lots of javadoc fixes
482 *
483 * Revision 1.3 2003/09/23 14:49:18 gus
484 * javadoc fix
485 *
486 * Revision 1.2 2002/11/25 16:16:43 gus
487 * fixing javadoc errors
488 *
489 * Revision 1.1.1.1 2002/06/05 21:56:32 root
490 * CS101 comes to Olin finally.
491 *
492 * Revision 1.4 1999/08/16 16:57:02 jsmthng
493 * Updated to make JavaDoc happy.
494 *
495 * Revision 1.3 1999/07/19 21:32:44 jsmthng
496 * Fix previous version, which had included a "this.what = a" in all
497 * constructors in order to placate Linux-Java, but which was confusing
498 * Win-NT Java2.
499 *
500 * Revision 1.2 1999/06/18 23:12:47 las
501 * Fixed embarrassingly idiotic bug in constructor (null test prior to
502 * assignment).
503 *
504 * Revision 1.1 1999/06/18 21:11:16 las
505 * Created cs101.lang package to house core additions such as Animate and
506 * AnimatorThread. Added those two Java files (interface Animate and
507 * class AnimatorThread) to the package. This will ultimately allow
508 * revision of all self-animating cs101 code.
509 *
510 */