| ||||
|
Code - Class EDU.oswego.cs.dl.util.concurrent.FJTask1 /* 2 File: Task.java 3 4 Originally written by Doug Lea and released into the public domain. 5 This may be used for any purposes whatsoever without acknowledgment. 6 Thanks for the assistance and support of Sun Microsystems Labs, 7 and everyone contributing, testing, and using this code. 8 9 History: 10 Date Who What 11 7Jan1999 dl first release 12 14jan1999 dl simplify start() semantics; 13 improve documentation 14 18Jan1999 dl Eliminate useless time-based waits. 15 7Mar1999 dl Add reset method, 16 add array-based composite operations 17 27Apr1999 dl Rename 18 */ 19 20 package EDU.oswego.cs.dl.util.concurrent; 21 22 23 /** 24 * Abstract base class for Fork/Join Tasks. 25 * 26 * <p> 27 * FJTasks are lightweight, stripped-down analogs of Threads. 28 * Many FJTasks share the same pool of Java threads. This is 29 * supported by the FJTaskRunnerGroup and FJTaskRunner classes, that 30 * mainly contain 31 * methods called only internally by FJTasks. 32 * FJTasks support versions of the most common methods found in class Thread, 33 * including start(), yield() and join(). However, they 34 * don't support priorities, ThreadGroups or other bookkeeping 35 * or control methods of class Thread. 36 * <p> 37 * FJTasks should normally be defined by subclassing and adding a run() method. 38 * Alternatively, static inner class <code>Wrap(Runnable r)</code> 39 * can be used to 40 * wrap an existing Runnable object in a FJTask. 41 * <p> 42 * <code>FJTaskRunnerGroup.execute(FJTask)</code> can be used to 43 * initiate a FJTask from a non-FJTask thread. 44 * And <code>FJTaskRunnerGroup.invoke(FJTask)</code> can be used to initiate 45 * a FJTask and then wait for it to complete before returning. 46 * These are the only entry-points from normal threads to FJTasks. 47 * Most FJTask methods themselves may only be called from within running FJTasks. 48 * They throw ClassCastExceptions if they are not, 49 * reflecting the fact that these methods 50 * can only be executed using FJTaskRunner threads, not generic 51 * java.lang.Threads. 52 * <p> 53 * There are three different ways to run a FJTask, 54 * with different scheduling semantics: 55 * <ul> 56 * <li> FJTask.start() (as well as FJTaskRunnerGroup.execute(FJTask)) 57 * behaves pretty much like Thread.start(). It enqueues a task to be 58 * run the next time any FJTaskRunner thread is otherwise idle. 59 * It maintains standard FIFO ordering with respect to 60 * the group of worker threads. 61 * <li> FJTask.fork() (as well as the two-task spawning method, 62 * coInvoke(task1, task2), and the array version 63 * coInvoke(FJTask[] tasks)) starts a task 64 * that will be executed in 65 * procedure-call-like LIFO order if executed by the 66 * same worker thread as the one that created it, but is FIFO 67 * with respect to other tasks if it is run by 68 * other worker threads. That is, earlier-forked 69 * tasks are preferred to later-forked tasks by other idle workers. 70 * Fork() is noticeably faster than start(), but can only be 71 * used when these scheduling semantics are acceptable. 72 * <li> FJTask.invoke(FJTask) just executes the run method 73 * of one task from within another. It is the analog of a 74 * direct call. 75 * </ul> 76 * <p> 77 * The main economies of FJTasks stem from the fact that 78 * FJTasks do not support blocking operations of any kind. 79 * FJTasks should just run to completion without 80 * issuing waits or performing blocking IO. 81 * There are several styles for creating the run methods that 82 * execute as tasks, including 83 * event-style methods, and pure computational methods. 84 * Generally, the best kinds of FJTasks are those that in turn 85 * generate other FJTasks. 86 * <p> 87 * There is nothing actually 88 * preventing you from blocking within a FJTask, and very short waits/blocks are 89 * completely well behaved. But FJTasks are not designed 90 * to support arbitrary synchronization 91 * since there is no way to suspend and resume individual tasks 92 * once they have begun executing. FJTasks should also be finite 93 * in duration -- they should not contain infinite loops. 94 * FJTasks that might need to perform a blocking 95 * action, or hold locks for extended periods, or 96 * loop forever can instead create normal 97 * java Thread objects that will do so. FJTasks are just not 98 * designed to support these things. 99 * FJTasks may however yield() control to allow their FJTaskRunner threads 100 * to run other tasks, 101 * and may wait for other dependent tasks via join(). These 102 * are the only coordination mechanisms supported by FJTasks. 103 * <p> 104 * FJTasks, and the FJTaskRunners that execute them are not 105 * intrinsically robust with respect to exceptions. 106 * A FJTask that aborts via an exception does not automatically 107 * have its completion flag (isDone) set. 108 * As with ordinary Threads, an uncaught exception will normally cause 109 * its FJTaskRunner thread to die, which in turn may sometimes 110 * cause other computations being performed to hang or abort. 111 * You can of course 112 * do better by trapping exceptions inside the run methods of FJTasks. 113 * <p> 114 * The overhead differences between FJTasks and Threads are substantial, 115 * especially when using fork() or coInvoke(). 116 * FJTasks can be two or three orders of magnitude faster than Threads, 117 * at least when run on JVMs with high-performance garbage collection 118 * (every FJTask quickly becomes garbage) and good native thread support. 119 * <p> 120 * Given these overhead savings, you might be tempted to use FJTasks for 121 * everything you would use a normal Thread to do. Don't. Java Threads 122 * remain better for general purpose thread-based programming. Remember 123 * that FJTasks cannot be used for designs involving arbitrary blocking 124 * synchronization or I/O. Extending FJTasks to support such capabilities 125 * would amount to re-inventing the Thread class, and would make them 126 * less optimal in the contexts that they were designed for. 127 * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] 128 * <p> 129 * @see FJTaskRunner 130 * @see FJTaskRunnerGroup 131 **/ 132 133 public abstract class FJTask implements Runnable { 134 135 /** 136 * The only status information associated with FJTasks is whether 137 * the they are considered to have completed. 138 * It is set true automatically within 139 * FJTaskRunner methods upon completion 140 * of the run method, or manually via cancel. 141 **/ 142 143 private volatile boolean done; // = false; 144 145 /** 146 * Return the FJTaskRunner thread running the current FJTask. 147 * Most FJTask methods are just relays to their current 148 * FJTaskRunners, that perform the indicated actions. 149 * @exception ClassCastException if caller thread is not a 150 * running FJTask. 151 **/ 152 153 public static FJTaskRunner getFJTaskRunner() { 154 return (FJTaskRunner)(Thread.currentThread()); 155 } 156 157 /** 158 * Return the FJTaskRunnerGroup of the thread running the current FJTask. 159 * @exception ClassCastException if caller thread is not a 160 * running FJTask. 161 **/ 162 public static FJTaskRunnerGroup getFJTaskRunnerGroup() { 163 return getFJTaskRunner().getGroup(); 164 } 165 166 167 /** 168 * Return true if current task has terminated or been cancelled. 169 * The method is a simple analog of the Thread.isAlive() 170 * method. However, it reports true only when the task has terminated 171 * or has been cancelled. It does not distinguish these two cases. 172 * And there is no way to determine whether a FJTask has been started 173 * or is currently executing. 174 **/ 175 176 public final boolean isDone() { return done; } 177 178 /** 179 * Indicate termination. Intended only to be called by FJTaskRunner. 180 * FJTasks themselves should use (non-final) method 181 * cancel() to suppress execution. 182 **/ 183 184 protected final void setDone() { done = true; } 185 186 /** 187 * Set the termination status of this task. This simple-minded 188 * analog of Thread.interrupt 189 * causes the task not to execute if it has not already been started. 190 * Cancelling a running FJTask 191 * has no effect unless the run method itself uses isDone() 192 * to probe cancellation and take appropriate action. 193 * Individual run() methods may sense status and 194 * act accordingly, normally by returning early. 195 **/ 196 197 public void cancel() { setDone(); } 198 199 200 /** 201 * Clear the termination status of this task. 202 * This method is intended to be used 203 * only as a means to allow task objects to be recycled. It should 204 * be called only when you are sure that the previous 205 * execution of this task has terminated and, if applicable, has 206 * been joined by all other waiting tasks. Usage in any other 207 * context is a very bad idea. 208 **/ 209 210 public void reset() { done = false; } 211 212 213 /** 214 * Execute this task. This method merely places the task in a 215 * group-wide scheduling queue. 216 * It will be run 217 * the next time any TaskRunner thread is otherwise idle. 218 * This scheduling maintains FIFO ordering of started tasks 219 * with respect to 220 * the group of worker threads. 221 * @exception ClassCastException if caller thread is not 222 * running in a FJTaskRunner thread. 223 **/ 224 225 public void start() { getFJTaskRunnerGroup().executeTask(this); } 226 227 228 /** 229 * Arrange for execution of a strictly dependent task. 230 * The task that will be executed in 231 * procedure-call-like LIFO order if executed by the 232 * same worker thread, but is FIFO with respect to other tasks 233 * forked by this thread when taken by other worker threads. 234 * That is, earlier-forked 235 * tasks are preferred to later-forked tasks by other idle workers. 236 * <p> 237 * Fork() is noticeably 238 * faster than start(). However, it may only 239 * be used for strictly dependent tasks -- generally, those that 240 * could logically be issued as straight method calls without 241 * changing the logic of the program. 242 * The method is optimized for use in parallel fork/join designs 243 * in which the thread that issues one or more forks 244 * cannot continue until at least some of the forked 245 * threads terminate and are joined. 246 * @exception ClassCastException if caller thread is not 247 * running in a FJTaskRunner thread. 248 **/ 249 250 public void fork() { getFJTaskRunner().push(this); } 251 252 /** 253 * Allow the current underlying FJTaskRunner thread to process other tasks. 254 * <p> 255 * Spinloops based on yield() are well behaved so long 256 * as the event or condition being waited for is produced via another 257 * FJTask. Additionally, you must never hold a lock 258 * while performing a yield or join. (This is because 259 * multiple FJTasks can be run by the same Thread during 260 * a yield. Since java locks are held per-thread, the lock would not 261 * maintain the conceptual exclusion you have in mind.) 262 * <p> 263 * Otherwise, spinloops using 264 * yield are the main construction of choice when a task must wait 265 * for a condition that it is sure will eventually occur because it 266 * is being produced by some other FJTask. The most common 267 * such condition is built-in: join() repeatedly yields until a task 268 * has terminated after producing some needed results. You can also 269 * use yield to wait for callbacks from other FJTasks, to wait for 270 * status flags to be set, and so on. However, in all these cases, 271 * you should be confident that the condition being waited for will 272 * occur, essentially always because it is produced by 273 * a FJTask generated by the current task, or one of its subtasks. 274 * 275 * @exception ClassCastException if caller thread is not 276 * running in a FJTaskRunner thread. 277 **/ 278 279 public static void yield() { getFJTaskRunner().taskYield(); } 280 281 /** 282 * Yield until this task isDone. 283 * Equivalent to <code>while(!isDone()) yield(); </code> 284 * @exception ClassCastException if caller thread is not 285 * running in a FJTaskRunner thread. 286 **/ 287 288 public void join() { getFJTaskRunner().taskJoin(this); } 289 290 /** 291 * Immediately execute task t by calling its run method. Has no 292 * effect if t has already been run or has been cancelled. 293 * It is equivalent to calling t.run except that it 294 * deals with completion status, so should always be used 295 * instead of directly calling run. 296 * The method can be useful 297 * when a computation has been packaged as a FJTask, but you just need to 298 * directly execute its body from within some other task. 299 **/ 300 301 public static void invoke(FJTask t) { 302 if (!t.isDone()) { 303 t.run(); 304 t.setDone(); 305 } 306 } 307 308 /** 309 * Fork both tasks and then wait for their completion. It behaves as: 310 * <pre> 311 * task1.fork(); task2.fork(); task2.join(); task1.join(); 312 * </pre> 313 * As a simple classic example, here is 314 * a class that computes the Fibonacci function: 315 * <pre> 316 * public class Fib extends FJTask { 317 * 318 * // Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1 319 * // fibonacci(0) = 0; 320 * // fibonacci(1) = 1. 321 * 322 * // Value to compute fibonacci function for. 323 * // It is replaced with the answer when computed. 324 * private volatile int number; 325 * 326 * public Fib(int n) { number = n; } 327 * 328 * public int getAnswer() { 329 * if (!isDone()) throw new Error("Not yet computed"); 330 * return number; 331 * } 332 * 333 * public void run() { 334 * int n = number; 335 * if (n > 1) { 336 * Fib f1 = new Fib(n - 1); 337 * Fib f2 = new Fib(n - 2); 338 * 339 * coInvoke(f1, f2); // run these in parallel 340 * 341 * // we know f1 and f2 are computed, so just directly access numbers 342 * number = f1.number + f2.number; 343 * } 344 * } 345 * 346 * public static void main(String[] args) { // sample driver 347 * try { 348 * int groupSize = 2; // 2 worker threads 349 * int num = 35; // compute fib(35) 350 * FJTaskRunnerGroup group = new FJTaskRunnerGroup(groupSize); 351 * Fib f = new Fib(num); 352 * group.invoke(f); 353 * int result = f.getAnswer(); 354 * System.out.println(" Answer: " + result); 355 * } 356 * catch (InterruptedException ex) { 357 * System.out.println("Interrupted"); 358 * } 359 * } 360 * } 361 * </pre> 362 * 363 * @exception ClassCastException if caller thread is not 364 * running in a FJTaskRunner thread. 365 **/ 366 367 public static void coInvoke(FJTask task1, FJTask task2) { 368 getFJTaskRunner().coInvoke(task1, task2); 369 } 370 371 372 /** 373 * Fork all tasks in array, and await their completion. 374 * Behaviorally equivalent to: 375 * <pre> 376 * for (int i = 0; i < tasks.length; ++i) tasks[i].fork(); 377 * for (int i = 0; i < tasks.length; ++i) tasks[i].join(); 378 * </pre> 379 **/ 380 381 public static void coInvoke(FJTask[] tasks) { 382 getFJTaskRunner().coInvoke(tasks); 383 } 384 385 /** 386 * A FJTask that holds a Runnable r, and calls r.run when executed. 387 * The class is a simple utilty to allow arbitrary Runnables 388 * to be used as FJTasks. 389 **/ 390 391 public static class Wrap extends FJTask { 392 protected final Runnable runnable; 393 public Wrap(Runnable r) { runnable = r; } 394 public void run() { runnable.run(); } 395 } 396 397 398 /** 399 * A <code>new Seq</code>, when executed, 400 * invokes each task provided in the constructor, in order. 401 * The class is a simple utility 402 * that makes it easier to create composite FJTasks. 403 **/ 404 public static class Seq extends FJTask { 405 protected final FJTask[] tasks; 406 407 /** 408 * Construct a Seq that, when executed, will process each of the 409 * tasks in the tasks array in order 410 **/ 411 public Seq(FJTask[] tasks) { 412 this.tasks = tasks; 413 } 414 415 /** 416 * Two-task constructor, for compatibility with previous release. 417 **/ 418 public Seq(FJTask task1, FJTask task2) { 419 this.tasks = new FJTask[] { task1, task2 }; 420 } 421 422 public void run() { 423 for (int i = 0; i < tasks.length; ++i) FJTask.invoke(tasks[i]); 424 } 425 } 426 427 /** 428 * Construct and return a FJTask object that, when executed, will 429 * invoke the tasks in the tasks array in array order 430 **/ 431 432 public static FJTask seq(FJTask[] tasks) { 433 return new Seq(tasks); 434 } 435 436 /** 437 * A <code>new Par</code>, when executed, 438 * runs the tasks provided in the constructor in parallel using 439 * coInvoke(tasks). 440 * The class is a simple utility 441 * that makes it easier to create composite FJTasks. 442 **/ 443 public static class Par extends FJTask { 444 protected final FJTask[] tasks; 445 446 /** 447 * Construct a Seq that, when executed, will process each of the 448 * tasks in the tasks array in parallel 449 **/ 450 public Par(FJTask[] tasks) { 451 this.tasks = tasks; 452 } 453 454 /** 455 * Two-task constructor, for compatibility with previous release. 456 **/ 457 public Par(FJTask task1, FJTask task2) { 458 this.tasks = new FJTask[] { task1, task2 }; 459 } 460 461 462 public void run() { 463 FJTask.coInvoke(tasks); 464 } 465 } 466 467 468 /** 469 * Construct and return a FJTask object that, when executed, will 470 * invoke the tasks in the tasks array in parallel using coInvoke 471 **/ 472 public static FJTask par(FJTask[] tasks) { 473 return new Par(tasks); 474 } 475 476 /** 477 * A <code>new Seq2(task1, task2)</code>, when executed, 478 * invokes task1 and then task2, in order. 479 * The class is a simple utility 480 * that makes it easier to create composite Tasks. 481 **/ 482 public static class Seq2 extends FJTask { 483 protected final FJTask fst; 484 protected final FJTask snd; 485 public Seq2(FJTask task1, FJTask task2) { 486 fst = task1; 487 snd = task2; 488 } 489 public void run() { 490 FJTask.invoke(fst); 491 FJTask.invoke(snd); 492 } 493 } 494 495 /** 496 * Construct and return a FJTask object that, when executed, will 497 * invoke task1 and task2, in order 498 **/ 499 500 public static FJTask seq(FJTask task1, FJTask task2) { 501 return new Seq2(task1, task2); 502 } 503 504 /** 505 * A <code>new Par(task1, task2)</code>, when executed, 506 * runs task1 and task2 in parallel using coInvoke(task1, task2). 507 * The class is a simple utility 508 * that makes it easier to create composite Tasks. 509 **/ 510 public static class Par2 extends FJTask { 511 protected final FJTask fst; 512 protected final FJTask snd; 513 public Par2(FJTask task1, FJTask task2) { 514 fst = task1; 515 snd = task2; 516 } 517 public void run() { 518 FJTask.coInvoke(fst, snd); 519 } 520 } 521 522 523 /** 524 * Construct and return a FJTask object that, when executed, will 525 * invoke task1 and task2, in parallel 526 **/ 527 public static FJTask par(FJTask task1, FJTask task2) { 528 return new Par2(task1, task2); 529 } 530 531 } 532 |
|||
Java API By Example, From Geeks To Geeks. |
Conditions of Use |
About Us
© 2002 - 2005, KickJava.com, or its affiliates
|