ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/RecursiveAction.java
Revision: 1.2
Committed: Mon Jul 20 21:45:06 2009 UTC (14 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.1: +2 -2 lines
Log Message:
whitespace

File Contents

# User Rev Content
1 dl 1.1 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3     * Expert Group and released to the public domain, as explained at
4     * http://creativecommons.org/licenses/publicdomain
5     */
6    
7     package jsr166y;
8    
9     /**
10     * Recursive resultless ForkJoinTasks. This class establishes
11     * conventions to parameterize resultless actions as <tt>Void</tt>
12     * ForkJoinTasks. Because <tt>null</tt> is the only valid value of
13     * <tt>Void</tt>, methods such as join always return <tt>null</tt>
14     * upon completion.
15 jsr166 1.2 *
16 dl 1.1 * <p><b>Sample Usages.</b> Here is a sketch of a ForkJoin sort that
17     * sorts a given <tt>long[]</tt> array:
18     *
19     * <pre>
20     * class SortTask extends RecursiveAction {
21     * final long[] array; final int lo; final int hi;
22     * SortTask(long[] array, int lo, int hi) {
23     * this.array = array; this.lo = lo; this.hi = hi;
24     * }
25     * protected void compute() {
26     * if (hi - lo &lt; THRESHOLD)
27     * sequentiallySort(array, lo, hi);
28     * else {
29     * int mid = (lo + hi) &gt;&gt;&gt; 1;
30     * invokeAll(new SortTask(array, lo, mid),
31     * new SortTask(array, mid, hi));
32     * merge(array, lo, hi);
33     * }
34     * }
35     * }
36     * </pre>
37     *
38     * You could then sort anArray by creating <tt>new SortTask(anArray, 0,
39     * anArray.length-1) </tt> and invoking it in a ForkJoinPool.
40     * As a more concrete simple example, the following task increments
41     * each element of an array:
42     * <pre>
43     * class IncrementTask extends RecursiveAction {
44     * final long[] array; final int lo; final int hi;
45     * IncrementTask(long[] array, int lo, int hi) {
46     * this.array = array; this.lo = lo; this.hi = hi;
47     * }
48     * protected void compute() {
49     * if (hi - lo &lt; THRESHOLD) {
50     * for (int i = lo; i &lt; hi; ++i)
51     * array[i]++;
52     * }
53     * else {
54     * int mid = (lo + hi) &gt;&gt;&gt; 1;
55     * invokeAll(new IncrementTask(array, lo, mid),
56     * new IncrementTask(array, mid, hi));
57     * }
58     * }
59     * }
60     * </pre>
61     *
62     *
63     * <p>The following example illustrates some refinements and idioms
64     * that may lead to better performance: RecursiveActions need not be
65     * fully recursive, so long as they maintain the basic
66     * divide-and-conquer approach. Here is a class that sums the squares
67     * of each element of a double array, by subdividing out only the
68     * right-hand-sides of repeated divisions by two, and keeping track of
69     * them with a chain of <tt>next</tt> references. It uses a dynamic
70     * threshold based on method <tt>surplus</tt>, but counterbalances
71     * potential excess partitioning by directly performing leaf actions
72     * on unstolen tasks rather than further subdividing.
73     *
74     * <pre>
75     * double sumOfSquares(ForkJoinPool pool, double[] array) {
76     * int n = array.length;
77     * int seqSize = 1 + n / (8 * pool.getParallelism());
78     * Applyer a = new Applyer(array, 0, n, seqSize, null);
79     * pool.invoke(a);
80     * return a.result;
81     * }
82     *
83     * class Applyer extends RecursiveAction {
84     * final double[] array;
85     * final int lo, hi, seqSize;
86     * double result;
87     * Applyer next; // keeps track of right-hand-side tasks
88     * Applyer(double[] array, int lo, int hi, int seqSize, Applyer next) {
89     * this.array = array; this.lo = lo; this.hi = hi;
90     * this.seqSize = seqSize; this.next = next;
91     * }
92     *
93     * double atLeaf(int l, int r) {
94     * double sum = 0;
95     * for (int i = l; i &lt; h; ++i) // perform leftmost base step
96     * sum += array[i] * array[i];
97     * return sum;
98     * }
99     *
100     * protected void compute() {
101     * int l = lo;
102     * int h = hi;
103     * Applyer right = null;
104     * while (h - l &gt; 1 &amp;&amp;
105     * ForkJoinWorkerThread.getEstimatedSurplusTaskCount() &lt;= 3) {
106     * int mid = (l + h) &gt;&gt;&gt; 1;
107     * right = new Applyer(array, mid, h, seqSize, right);
108     * right.fork();
109     * h = mid;
110     * }
111     * double sum = atLeaf(l, h);
112     * while (right != null) {
113     * if (right.tryUnfork()) // directly calculate if not stolen
114     * sum += right.atLeaf(right.lo, right.hi);
115     * else {
116     * right.helpJoin();
117     * sum += right.result;
118     * }
119     * right = right.next;
120     * }
121     * result = sum;
122     * }
123     * }
124     * </pre>
125     */
126     public abstract class RecursiveAction extends ForkJoinTask<Void> {
127    
128     /**
129 jsr166 1.2 * The main computation performed by this task.
130 dl 1.1 */
131     protected abstract void compute();
132    
133     /**
134     * Always returns null
135     */
136     public final Void getRawResult() { return null; }
137    
138     /**
139     * Requires null completion value.
140     */
141     protected final void setRawResult(Void mustBeNull) { }
142    
143     /**
144     * Implements execution conventions for RecursiveActions
145     */
146     protected final boolean exec() {
147     compute();
148     return true;
149     }
150    
151     }