ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/RecursiveAction.java
Revision: 1.1
Committed: Tue Jan 6 14:30:31 2009 UTC (15 years, 4 months ago) by dl
Branch: MAIN
Log Message:
Refactored and repackaged ForkJoin classes

File Contents

# Content
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 *
16 * <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 * The main computation performed by this task.
130 */
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 }