ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166y/RecursiveAction.java
Revision: 1.19
Committed: Mon Jun 27 02:47:32 2011 UTC (12 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.18: +20 -8 lines
Log Message:
even more SortTask improvements

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