/* * $Id: AnimatorThread.java,v 1.5 2003/09/23 15:31:11 gus Exp $ * * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's AP Group. * For more information, see the * CS101 homepage or email . * * Copyright (C) 1999 Massachusetts Institute of Technology. * Please do not redistribute without obtaining permission. */ package cs101.lang; /** * This class replaces Thread as a way to animate autonomous objects. * An AnimatorThread can be passed any object that implements the * Animate interface. The AnimatorThread (when started) begins * executing at the Animate's act() method. * * Instances of this class provide safe ways to start, stop, suspend, * and resume execution through the use of startExecution(), * stopExecution(), suspendExecution() and resumeExecution() methods. * * Unlike java.lang.Thread, this class cannot be extended. * * Copyright 1999 Massachusetts Institute of Technology * * @see Thread * @see cs101.lang.Animate * @see #startExecution() * @see #stopExecution() * @see #suspendExecution() * @see #resumeExecution() * * @author Lynn Andrea Stein, las@ai.mit.edu * @version $Id: AnimatorThread.java,v 1.5 2003/09/23 15:31:11 gus Exp $ * */ public final class AnimatorThread extends Thread { /* CONSTANTS */ /** * These constants allow mnemonic access to AnimateObject's final * constructor argument, i.e., should the object start running on * construction or on (a subsequent) call to a separate start() * method? * * @see #AnimatorThread( Animate, boolean ) */ public static final boolean START_IMMEDIATELY = true, DONT_START_YET = false; /** * Default values for sleepMinInterval, sleepRange. Static so * they're available to constructors. * * These default values are chosen to allow GUI events to be * easily perceived. * */ private static final long DEFAULT_SLEEP_MIN_INTERVAL = 200, DEFAULT_SLEEP_RANGE = 400; /* FIELDS */ /** * These private fields control the state of execution of this * object's animacy. They supercede the now-deprecated * Thread.stop()/Thread.suspend() regime of Java 1.0.

* * Note that they must be volatile in order to ensure correct * access by the animating Thread. * * @see #stopExecution() * @see #suspendExecution() * @see #resumeExecution() */ private volatile boolean isStopped = false, isSuspended = false; /** * This object exists only to be a unique privately held object * on which wait() and notify() can be invoked in cases of ersatz * suspension. This is a part of the solution to handle the * now-deprecated Thread.suspend() regime of Java 1.0.

* * @see #stopExecution() * @see #suspendExecution() * @see #resumeExecution() */ private final Object suspendLock = new Object(); /** * These values control the sleep interval between calls to the * Animate's act() method: the smallest interval for which this * AnimatorThread will sleep and the variance above this interval. * In no case will the minimum sleep time be less than * this.sleepMinInterval; it could be as long as * this.sleepMinInterval + this.sleepRange. * * The default values are set by * AnimatorThread.DEFAULT_SLEEP_MIN_INTERVAL and * AnimatorThread.DEFAULT_SLEEP_RANGE. These values can be * overriden either by the constructor or by means of a public * setter method. * * @see #AnimatorThread( Animate, long, long ) * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) * @see #DEFAULT_SLEEP_MIN_INTERVAL * @see #DEFAULT_SLEEP_RANGE */ private long sleepMinInterval, sleepRange; /** * This is the object that this AnimatorThread will Animate. * * @see Animate */ private final Animate what; /* CONSTRUCTORS */ /** * This constructor requires the Animate that is to be animated. * Once the AnimatorThread being constructed is started (using its * start() method), the Animate's act() method will be called * periodically, with the interval between calls controlled by * sleepMinInterval and sleepRange. * * @param a the Animate to be animated. * * @see Animate * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a ) { this( a, AnimatorThread.DONT_START_YET ); } /** * This constructor requires the Animate that is to be animated and * a boolean value (expected to be one of * AnimatorThread.START_IMMEDIATELY or * AnimatorThread.DONT_START_YET) that determines whether this * AnimatorThread should start running as the last step of its * construction. If this boolean's value is START_IMMEDIATELY, * execution will begin as soon as this constructor exits. * Otherwise, a subsequent call to the AnimatorThread's start() * method is required. * * It is expected that this boolean will generally be * AnimatorThread.START_IMMEDIATELY as the default value of the * one-arg constructor is AnimatorThread.DONT_START_YET. * * @param a the Animate to be animated. * @param startImmediately one of AnimatorThread.START_IMMEDIATELY * or AnimatorThread.DONT_START_YET * * @see Animate * @see #AnimatorThread( Animate ) * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a, boolean startImmediately ) { this( a, startImmediately, AnimatorThread.DEFAULT_SLEEP_MIN_INTERVAL, AnimatorThread.DEFAULT_SLEEP_RANGE ); } /** * This constructor requires the Animate that is to be animated and * a long representing the desired variance in sleep times between * calls to the Animate's act() method. This constructor requires * an additional call to the AnimatorThread's start() method. * * The sleep time between calls to the Animate's act() will vary * between this.sleepMinInterval and this.sleepMinInterval + * sleepRange. * * @param a the Animate to be animated. * @param sleepRange the desired variance in sleep times above and * beyond sleepMinInterval * * @see Animate * @see #AnimatorThread( Animate ) * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a, long sleepRange ) { this( a, AnimatorThread.DONT_START_YET, sleepRange ); } /** * This constructor requires the Animate that is to be animated, a * boolean reflecting whether execution should begin immediately, * and a long representing the desired variance in sleep times * between calls to the Animate's act() method. * * @param a the Animate to be animated. * @param startImmediately one of AnimatorThread.START_IMMEDIATELY * or AnimatorThread.DONT_START_YET * @param sleepRange the desired variance in sleep times above and * beyond sleepMinInterval * * @see Animate * @see #AnimatorThread( Animate, boolean ) * @see #AnimatorThread( Animate, long ) * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a, boolean startImmediately, long sleepRange ) { this( a, startImmediately, sleepRange, AnimatorThread.DEFAULT_SLEEP_RANGE ); } /** * This constructor requires the Animate that is to be animated and * two longs representing the desired variance in sleep times and * the desired minimum sleep interval between calls to the Animate's * act() method. This constructor requires an additional call to * the AnimatorThread's start() method. * * The sleep time between calls to the Animate's act() will vary * between sleepMinInterval and sleepMinInterval + sleepRange. * * @param a the Animate to be animated. * @param sleepRange the desired variance in sleep times above and * beyond sleepMinInterval * @param sleepMinInterval the minimum interval between calls to * the Animate's act() method * * @see Animate * @see #AnimatorThread( Animate ) * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a, long sleepRange, long sleepMinInterval ) { this( a, AnimatorThread.DONT_START_YET, sleepRange, sleepMinInterval ); } /** * This constructor requires the Animate that is to be animated, a * boolean reflecting whether execution should begin immediately, * and two longs representing the desired variance in sleep times * and the desired minimum sleep interval between calls to the * Animate's act() method. * * @param a the Animate to be animated. * @param startImmediately one of AnimatorThread.START_IMMEDIATELY * or AnimatorThread.DONT_START_YET * @param sleepRange the desired variance in sleep times above and * beyond sleepMinInterval * @param sleepMinInterval the minimum interval between calls to * the Animate's act() method * * @see Animate * @see #AnimatorThread( Animate, boolean ) * @see #AnimatorThread( Animate, long, long ) * @see #start() * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public AnimatorThread ( Animate a, boolean startImmediately, long sleepRange, long sleepMinInterval ) { super(); this.what = a; if ( this.what == null ) { throw new IllegalArgumentException("Cannot start an AnimatorThread " + "without supplying an Animate!"); } this.sleepRange = sleepRange; this.sleepMinInterval = sleepMinInterval; if ( startImmediately ) { this.start(); } } /** * Repeatedly invoke your Animate's act() method, sleeping between * invocations. * * This method contains an amazing amount of hair to deal with * suspension, resumption, and stopping of AnimatorThreads. See * theJavaSoft statement on Thread primitive deprication. * * @see Animate * @see #setSleepMinInterval(long) * @see #setSleepRange( long ) */ public void run() { RUN_LOOP: while ( ! this.isStopped ) { if ( this.isSuspended ) { synchronized ( this.suspendLock ) { while ( this.isSuspended ) { try { this.suspendLock.wait(); } catch ( InterruptedException e ) { } finally { if ( this.isStopped ) { break RUN_LOOP; } } } } } try { Thread.sleep( Math.round( Math.random() * this.sleepRange ) + this.sleepMinInterval ); this.what.act(); } catch ( InterruptedException e ) { } } } /** * Begin execution. This causes the AnimatorThread to periodically * call its Animate's act() method. (Same as this.startExecution().) * * @see Animate * @see #AnimatorThread(Animate) * @see Thread#start() */ public void start() { this.startExecution(); } /** * Begin execution. This causes the AnimatorThread to periodically * call its Animate's act() method. * * @see Animate * @see #AnimatorThread(Animate) * @see Thread#start() */ public void startExecution() { if (( ! this.isStopped ) && ( ! this.isAlive() )) { super.start(); } } /** * Terminates execution. This causes the AnimatorThread to cease * execution immediately. Once stopped, an AnimatorThread cannot * be restarted. * * Safely replaces Thread's (deprecated) stop() method. * * @see Thread#stop() */ public void stopExecution() { this.isStopped = true; // Set state this.interrupt(); // Wake if sleeping, waiting, etc. } /** * Temporarily suspends execution. This causes the AnimatorThread * to suspend execution following the next act() of its Animate. * Periodic execution of the Animate's act() method can be restarted * using resumeExecution(). * * Safely replaces Thread's (deprecated) suspend() method. * * @see #resumeExecution() * @see Thread#suspend() * */ public void suspendExecution() { synchronized ( this.suspendLock ) // I suspect this { // synchronization is this.isSuspended = true; // unnecessary.... } } /** * Resumes execution after a temporary suspension (using * suspendExecution()). * * Safely replaces Thread's (deprecated) resume() method. * * @see #suspendExecution() * @see Thread#resume() * */ public void resumeExecution() { synchronized ( this.suspendLock ) { this.isSuspended = false; this.suspendLock.notify(); } } /** * Gives access to this AnimatorThread's sleep minimum. * This controls the smallest interval for which this AnimatorThread * will sleep, i.e., the minimum time between actions for the * Animate that it animates. * * If sleepMinInterval is set to 0, it is possible that this * AnimatorThread will prevent execution by other Threads by fully * occupying the CPU. * * @see #AnimatorThread( Animate, boolean, long, long ) * @see #setSleepRange( long ) */ public void setSleepMinInterval( long minInterval ) { this.sleepMinInterval = minInterval; } /** * This controls the possible range of durations for AnimatorThread * to sleep, i.e., the possible time between actions for the Animate * that it animates. In no case will the minimum sleep time be less * than this.sleepMinInterval; it could be as long as * this.sleepMinInterval + this.sleepRange. * * Gives access to this AnimatorThread's sleep variance. If 0, this * AnimatorThread will sleep for the same amount of time between each * invocation of the Animate's act() method. * * @see #AnimatorThread( Animate, boolean, long, long ) * @see #setSleepRange( long ) */ public void setSleepRange( long range ) { this.sleepRange = range; } } /* * $Log: AnimatorThread.java,v $ * Revision 1.5 2003/09/23 15:31:11 gus * more javadoc fixes * * Revision 1.4 2003/09/23 15:02:58 gus * Lots of javadoc fixes * * Revision 1.3 2003/09/23 14:49:18 gus * javadoc fix * * Revision 1.2 2002/11/25 16:16:43 gus * fixing javadoc errors * * Revision 1.1.1.1 2002/06/05 21:56:32 root * CS101 comes to Olin finally. * * Revision 1.4 1999/08/16 16:57:02 jsmthng * Updated to make JavaDoc happy. * * Revision 1.3 1999/07/19 21:32:44 jsmthng * Fix previous version, which had included a "this.what = a" in all * constructors in order to placate Linux-Java, but which was confusing * Win-NT Java2. * * Revision 1.2 1999/06/18 23:12:47 las * Fixed embarrassingly idiotic bug in constructor (null test prior to * assignment). * * Revision 1.1 1999/06/18 21:11:16 las * Created cs101.lang package to house core additions such as Animate and * AnimatorThread. Added those two Java files (interface Animate and * class AnimatorThread) to the package. This will ultimately allow * revision of all self-animating cs101 code. * */