--- jsr166/src/jsr166y/ForkJoinTask.java 2009/08/02 22:58:50 1.31 +++ jsr166/src/jsr166y/ForkJoinTask.java 2009/08/05 11:09:28 1.40 @@ -12,6 +12,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.RandomAccess; import java.util.Map; import java.util.WeakHashMap; @@ -54,7 +55,7 @@ import java.util.WeakHashMap; * restriction is in part enforced by not permitting checked * exceptions such as {@code IOExceptions} to be thrown. However, * computations may still encounter unchecked exceptions, that are - * rethrown to callers attempting join them. These exceptions may + * rethrown to callers attempting to join them. These exceptions may * additionally include RejectedExecutionExceptions stemming from * internal resource exhaustion such as failure to allocate internal * task queues. @@ -67,15 +68,29 @@ import java.util.WeakHashMap; * execute other tasks while awaiting joins, which is sometimes more * efficient but only applies when all subtasks are known to be * strictly tree-structured. Method {@link #invoke} is semantically - * equivalent to {@code fork(); join()} but always attempts to - * begin execution in the current thread. The "quiet" forms - * of these methods do not extract results or report exceptions. These + * equivalent to {@code fork(); join()} but always attempts to begin + * execution in the current thread. The "quiet" forms of + * these methods do not extract results or report exceptions. These * may be useful when a set of tasks are being executed, and you need * to delay processing of results or exceptions until all complete. * Method {@code invokeAll} (available in multiple versions) * performs the most common form of parallel invocation: forking a set * of tasks and joining them all. * + *

The execution status of tasks may be queried at several levels + * of detail: {@link #isDone} is true if a task completed in any way + * (including the case where a task was cancelled without executing); + * {@link #isCancelled} is true if completion was due to cancellation; + * {@link #isCompletedNormally} is true if a task completed without + * cancellation or encountering an exception; {@link + * #isCompletedExceptionally} is true if if the task encountered an + * exception (in which case {@link #getException} returns the + * exception); {@link #isCancelled} is true if the task was cancelled + * (in which case {@link #getException} returns a {@link + * java.util.concurrent.CancellationException}); and {@link + * #isCompletedAbnormally} is true if a task was either cancelled or + * encountered an exception. + * *

The ForkJoinTask class is not usually directly subclassed. * Instead, you subclass one of the abstract classes that support a * particular style of fork/join processing, typically {@link @@ -85,42 +100,41 @@ import java.util.WeakHashMap; * established in a constructor, and then defines a {@code compute} * method that somehow uses the control methods supplied by this base * class. While these methods have {@code public} access (to allow - * instances of different task subclasses to call each others + * instances of different task subclasses to call each other's * methods), some of them may only be called from within other * ForkJoinTasks (as may be determined using method {@link * #inForkJoinPool}). Attempts to invoke them in other contexts * result in exceptions or errors, possibly including * ClassCastException. * - *

Most base support methods are {@code final} because their - * implementations are intrinsically tied to the underlying - * lightweight task scheduling framework, and so cannot be overridden. - * Developers creating new basic styles of fork/join processing should - * minimally implement {@code protected} methods - * {@link #exec}, {@link #setRawResult}, and - * {@link #getRawResult}, while also introducing an abstract - * computational method that can be implemented in its subclasses, - * possibly relying on other {@code protected} methods provided - * by this class. + *

Most base support methods are {@code final}, to prevent + * overriding of implementations that are intrinsically tied to the + * underlying lightweight task scheduling framework. Developers + * creating new basic styles of fork/join processing should minimally + * implement {@code protected} methods {@link #exec}, {@link + * #setRawResult}, and {@link #getRawResult}, while also introducing + * an abstract computational method that can be implemented in its + * subclasses, possibly relying on other {@code protected} methods + * provided by this class. * *

ForkJoinTasks should perform relatively small amounts of - * computations, otherwise splitting into smaller tasks. As a very - * rough rule of thumb, a task should perform more than 100 and less - * than 10000 basic computational steps. If tasks are too big, then - * parallelism cannot improve throughput. If too small, then memory - * and internal task maintenance overhead may overwhelm processing. + * computation. Large tasks should be split into smaller subtasks, + * usually via recursive decomposition. As a very rough rule of thumb, + * a task should perform more than 100 and less than 10000 basic + * computational steps. If tasks are too big, then parallelism cannot + * improve throughput. If too small, then memory and internal task + * maintenance overhead may overwhelm processing. * - *

This class provides {@code adapt} methods for {@link - * java.lang.Runnable} and {@link java.util.concurrent.Callable}, that - * may be of use when mixing execution of ForkJoinTasks with other - * kinds of tasks. When all tasks are of this form, consider using a - * pool in {@link ForkJoinPool#setAsyncMode}. + *

This class provides {@code adapt} methods for {@link Runnable} + * and {@link Callable}, that may be of use when mixing execution of + * {@code ForkJoinTasks} with other kinds of tasks. When all tasks + * are of this form, consider using a pool in + * {@linkplain ForkJoinPool#setAsyncMode async mode}. * - *

ForkJoinTasks are {@code Serializable}, which enables them - * to be used in extensions such as remote execution frameworks. It is - * in general sensible to serialize tasks only before or after, but - * not during execution. Serialization is not relied on during - * execution itself. + *

ForkJoinTasks are {@code Serializable}, which enables them to be + * used in extensions such as remote execution frameworks. It is + * sensible to serialize tasks only before or after, but not during, + * execution. Serialization is not relied on during execution itself. * * @since 1.7 * @author Doug Lea @@ -378,10 +392,13 @@ public abstract class ForkJoinTask im /** * Returns result or throws exception using j.u.c.Future conventions. - * Only call when {@code isDone} known to be true. + * Only call when {@code isDone} known to be true or thread known + * to be interrupted. */ private V reportFutureResult() - throws ExecutionException, InterruptedException { + throws InterruptedException, ExecutionException { + if (Thread.interrupted()) + throw new InterruptedException(); int s = status & COMPLETION_MASK; if (s < NORMAL) { Throwable ex; @@ -389,8 +406,6 @@ public abstract class ForkJoinTask im throw new CancellationException(); if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) throw new ExecutionException(ex); - if (Thread.interrupted()) - throw new InterruptedException(); } return getRawResult(); } @@ -401,17 +416,18 @@ public abstract class ForkJoinTask im */ private V reportTimedFutureResult() throws InterruptedException, ExecutionException, TimeoutException { + if (Thread.interrupted()) + throw new InterruptedException(); Throwable ex; int s = status & COMPLETION_MASK; if (s == NORMAL) return getRawResult(); - if (s == CANCELLED) + else if (s == CANCELLED) throw new CancellationException(); - if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) throw new ExecutionException(ex); - if (Thread.interrupted()) - throw new InterruptedException(); - throw new TimeoutException(); + else + throw new TimeoutException(); } // internal execution methods @@ -529,10 +545,9 @@ public abstract class ForkJoinTask im /** * Commences performing this task, awaits its completion if - * necessary, and return its result. + * necessary, and return its result, or throws an (unchecked) + * exception if the underlying computation did so. * - * @throws Throwable (a RuntimeException, Error, or unchecked - * exception) if the underlying computation did so * @return the computed result */ public final V invoke() { @@ -543,8 +558,13 @@ public abstract class ForkJoinTask im } /** - * Forks the given tasks, returning when {@code isDone} holds - * for each task or an exception is encountered. + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If either task encounters an + * exception, the other one may be, but is not guaranteed to be, + * cancelled. If both tasks throw an exception, then this method + * throws one of them. The individual status of each task may be + * checked using {@link #getException()} and related methods. * *

This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -555,7 +575,6 @@ public abstract class ForkJoinTask im * @param t1 the first task * @param t2 the second task * @throws NullPointerException if any task is null - * @throws RuntimeException or Error if a task did so */ public static void invokeAll(ForkJoinTask t1, ForkJoinTask t2) { t2.fork(); @@ -565,9 +584,13 @@ public abstract class ForkJoinTask im /** * Forks the given tasks, returning when {@code isDone} holds for - * each task or an exception is encountered. If any task - * encounters an exception, others may be, but are not guaranteed - * to be, cancelled. + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If any task encounters an + * exception, others may be, but are not guaranteed to be, + * cancelled. If more than one task encounters an exception, then + * this method throws any one of these exceptions. The individual + * status of each task may be checked using {@link #getException()} + * and related methods. * *

This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -575,12 +598,8 @@ public abstract class ForkJoinTask im * result in exceptions or errors, possibly including {@code * ClassCastException}. * - *

Overloadings of this method exist for the special cases - * of one to four arguments. - * * @param tasks the tasks - * @throws NullPointerException if tasks or any element are null - * @throws RuntimeException or Error if any task did so + * @throws NullPointerException if any task is null */ public static void invokeAll(ForkJoinTask... tasks) { Throwable ex = null; @@ -616,10 +635,16 @@ public abstract class ForkJoinTask im } /** - * Forks all tasks in the collection, returning when {@code - * isDone} holds for each task or an exception is encountered. - * If any task encounters an exception, others may be, but are - * not guaranteed to be, cancelled. + * Forks all tasks in the specified collection, returning when + * {@code isDone} holds for each task or an (unchecked) exception + * is encountered. If any task encounters an exception, others + * may be, but are not guaranteed to be, cancelled. If more than + * one task encounters an exception, then this method throws any + * one of these exceptions. The individual status of each task + * may be checked using {@link #getException()} and related + * methods. The behavior of this operation is undefined if the + * specified collection is modified while the operation is in + * progress. * *

This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -630,10 +655,9 @@ public abstract class ForkJoinTask im * @param tasks the collection of tasks * @return the tasks argument, to simplify usage * @throws NullPointerException if tasks or any element are null - * @throws RuntimeException or Error if any task did so */ public static > Collection invokeAll(Collection tasks) { - if (!(tasks instanceof List)) { + if (!(tasks instanceof RandomAccess) || !(tasks instanceof List)) { invokeAll(tasks.toArray(new ForkJoinTask[tasks.size()])); return tasks; } @@ -674,35 +698,13 @@ public abstract class ForkJoinTask im } /** - * Returns {@code true} if the computation performed by this task - * has completed (or has been cancelled). - * - * @return {@code true} if this computation has completed - */ - public final boolean isDone() { - return status < 0; - } - - /** - * Returns {@code true} if this task was cancelled. - * - * @return {@code true} if this task was cancelled - */ - public final boolean isCancelled() { - return (status & COMPLETION_MASK) == CANCELLED; - } - - /** - * Asserts that the results of this task's computation will not be - * used. If a cancellation occurs before attempting to execute this - * task, execution will be suppressed, {@link #isCancelled} - * will report true, and {@link #join} will result in a - * {@code CancellationException} being thrown. Otherwise, when - * cancellation races with completion, there are no guarantees - * about whether {@code isCancelled} will report {@code true}, - * whether {@code join} will return normally or via an exception, - * or whether these behaviors will remain consistent upon repeated - * invocation. + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, has already been + * cancelled, or could not be cancelled for some other reason. If + * successful, and this task has not started when cancel is + * called, execution of this task is suppressed, {@link + * #isCancelled} will report true, and {@link #join} will result + * in a {@code CancellationException} being thrown. * *

This method may be overridden in subclasses, but if so, must * still ensure that these minimal properties hold. In particular, @@ -714,7 +716,7 @@ public abstract class ForkJoinTask im * invoke {@link #completeExceptionally}. * * @param mayInterruptIfRunning this value is ignored in the - * default implementation because tasks are not in general + * default implementation because tasks are not * cancelled via interruption * * @return {@code true} if this task is now cancelled @@ -724,6 +726,14 @@ public abstract class ForkJoinTask im return (status & COMPLETION_MASK) == CANCELLED; } + public final boolean isDone() { + return status < 0; + } + + public final boolean isCancelled() { + return (status & COMPLETION_MASK) == CANCELLED; + } + /** * Returns {@code true} if this task threw an exception or was cancelled. * @@ -734,6 +744,26 @@ public abstract class ForkJoinTask im } /** + * Returns {@code true} if this task completed without throwing an + * exception and was not cancelled. + * + * @return {@code true} if this task completed without throwing an + * exception and was not cancelled + */ + public final boolean isCompletedNormally() { + return (status & COMPLETION_MASK) == NORMAL; + } + + /** + * Returns {@code true} if this task threw an exception. + * + * @return {@code true} if this task threw an exception + */ + public final boolean isCompletedExceptionally() { + return (status & COMPLETION_MASK) == EXCEPTIONAL; + } + + /** * Returns the exception thrown by the base computation, or a * {@code CancellationException} if cancelled, or {@code null} if * none or if the method has not yet completed. @@ -742,11 +772,9 @@ public abstract class ForkJoinTask im */ public final Throwable getException() { int s = status & COMPLETION_MASK; - if (s >= NORMAL) - return null; - if (s == CANCELLED) - return new CancellationException(); - return exceptionMap.get(this); + return ((s >= NORMAL) ? null : + (s == CANCELLED) ? new CancellationException() : + exceptionMap.get(this)); } /** @@ -832,7 +860,9 @@ public abstract class ForkJoinTask im } /** - * Possibly executes other tasks until this task is ready. + * Possibly executes other tasks until this task is ready. This + * method may be useful when processing collections of tasks when + * some have been cancelled or otherwise known to have aborted. * *

This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -877,9 +907,10 @@ public abstract class ForkJoinTask im /** * Possibly executes tasks until the pool hosting the current task - * {@link ForkJoinPool#isQuiescent}. This method may be of use in - * designs in which many tasks are forked, but none are explicitly - * joined, instead executing them until all are processed. + * {@link ForkJoinPool#isQuiescent is quiescent}. This method may + * be of use in designs in which many tasks are forked, but none + * are explicitly joined, instead executing them until all are + * processed. * *

This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -1023,11 +1054,10 @@ public abstract class ForkJoinTask im * called otherwise. The return value controls whether this task * is considered to be done normally. It may return false in * asynchronous actions that require explicit invocations of - * {@link #complete} to become joinable. It may throw exceptions - * to indicate abnormal exit. + * {@link #complete} to become joinable. It may also throw an + * (unchecked) exception to indicate abnormal exit. * * @return {@code true} if completed normally - * @throws Error or RuntimeException if encountered during computation */ protected abstract boolean exec();