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 */