ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/RecursiveAction.java
Revision: 1.14
Committed: Sat Sep 18 19:53:08 2010 UTC (13 years, 8 months ago) by dl
Branch: MAIN
Changes since 1.13: +1 -1 lines
Log Message:
helpJoin -> join in demo code

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 jsr166 1.10 * A recursive resultless {@link ForkJoinTask}. This class
11     * establishes conventions to parameterize resultless actions as
12     * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the
13     * only valid value of type {@code Void}, methods such as join always
14     * return {@code null} 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 jsr166 1.3 * sorts a given {@code long[]} array:
18 dl 1.1 *
19 jsr166 1.4 * <pre> {@code
20 dl 1.1 * 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 jsr166 1.4 * if (hi - lo < THRESHOLD)
27 dl 1.1 * sequentiallySort(array, lo, hi);
28     * else {
29 jsr166 1.4 * int mid = (lo + hi) >>> 1;
30 dl 1.1 * invokeAll(new SortTask(array, lo, mid),
31     * new SortTask(array, mid, hi));
32     * merge(array, lo, hi);
33     * }
34     * }
35 jsr166 1.4 * }}</pre>
36 dl 1.1 *
37 jsr166 1.7 * You could then sort {@code anArray} by creating {@code new
38     * SortTask(anArray, 0, anArray.length-1) } and invoking it in a
39     * ForkJoinPool. As a more concrete simple example, the following
40     * task increments each element of an array:
41 jsr166 1.4 * <pre> {@code
42 dl 1.1 * class IncrementTask extends RecursiveAction {
43     * final long[] array; final int lo; final int hi;
44     * IncrementTask(long[] array, int lo, int hi) {
45     * this.array = array; this.lo = lo; this.hi = hi;
46     * }
47     * protected void compute() {
48 jsr166 1.4 * if (hi - lo < THRESHOLD) {
49     * for (int i = lo; i < hi; ++i)
50 dl 1.1 * array[i]++;
51     * }
52     * else {
53 jsr166 1.4 * int mid = (lo + hi) >>> 1;
54 dl 1.1 * invokeAll(new IncrementTask(array, lo, mid),
55     * new IncrementTask(array, mid, hi));
56     * }
57     * }
58 jsr166 1.4 * }}</pre>
59 dl 1.1 *
60     * <p>The following example illustrates some refinements and idioms
61     * that may lead to better performance: RecursiveActions need not be
62     * fully recursive, so long as they maintain the basic
63     * divide-and-conquer approach. Here is a class that sums the squares
64     * of each element of a double array, by subdividing out only the
65     * right-hand-sides of repeated divisions by two, and keeping track of
66 jsr166 1.3 * them with a chain of {@code next} references. It uses a dynamic
67 dl 1.12 * threshold based on method {@code getSurplusQueuedTaskCount}, but
68 dl 1.11 * counterbalances potential excess partitioning by directly
69     * performing leaf actions on unstolen tasks rather than further
70     * subdividing.
71 dl 1.1 *
72 jsr166 1.4 * <pre> {@code
73 dl 1.1 * double sumOfSquares(ForkJoinPool pool, double[] array) {
74     * int n = array.length;
75 dl 1.13 * Applyer a = new Applyer(array, 0, n, null);
76 dl 1.1 * pool.invoke(a);
77     * return a.result;
78     * }
79     *
80     * class Applyer extends RecursiveAction {
81     * final double[] array;
82 dl 1.13 * final int lo, hi;
83 dl 1.1 * double result;
84     * Applyer next; // keeps track of right-hand-side tasks
85 dl 1.13 * Applyer(double[] array, int lo, int hi, Applyer next) {
86 dl 1.1 * this.array = array; this.lo = lo; this.hi = hi;
87 dl 1.13 * this.next = next;
88 dl 1.1 * }
89     *
90 dl 1.13 * double atLeaf(int l, int h) {
91 dl 1.1 * double sum = 0;
92 jsr166 1.4 * for (int i = l; i < h; ++i) // perform leftmost base step
93 dl 1.1 * sum += array[i] * array[i];
94     * return sum;
95     * }
96     *
97     * protected void compute() {
98     * int l = lo;
99     * int h = hi;
100     * Applyer right = null;
101 dl 1.8 * while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
102 jsr166 1.4 * int mid = (l + h) >>> 1;
103 dl 1.13 * right = new Applyer(array, mid, h, right);
104 dl 1.1 * right.fork();
105     * h = mid;
106     * }
107     * double sum = atLeaf(l, h);
108     * while (right != null) {
109     * if (right.tryUnfork()) // directly calculate if not stolen
110     * sum += right.atLeaf(right.lo, right.hi);
111     * else {
112 dl 1.14 * right.join();
113 dl 1.1 * sum += right.result;
114     * }
115     * right = right.next;
116     * }
117     * result = sum;
118     * }
119 jsr166 1.4 * }}</pre>
120 jsr166 1.6 *
121     * @since 1.7
122     * @author Doug Lea
123 dl 1.1 */
124     public abstract class RecursiveAction extends ForkJoinTask<Void> {
125 dl 1.9 private static final long serialVersionUID = 5232453952276485070L;
126 dl 1.1
127     /**
128 jsr166 1.2 * The main computation performed by this task.
129 dl 1.1 */
130     protected abstract void compute();
131    
132     /**
133 jsr166 1.5 * Always returns null.
134 dl 1.1 */
135     public final Void getRawResult() { return null; }
136    
137     /**
138     * Requires null completion value.
139     */
140     protected final void setRawResult(Void mustBeNull) { }
141    
142     /**
143 jsr166 1.5 * Implements execution conventions for RecursiveActions.
144 dl 1.1 */
145     protected final boolean exec() {
146     compute();
147     return true;
148     }
149    
150     }