1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/publicdomain/zero/1.0/
  34  */
  35 
  36 package java.util.concurrent;
  37 
  38 /**
  39  * A recursive resultless {@link ForkJoinTask}.  This class
  40  * establishes conventions to parameterize resultless actions as
  41  * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the
  42  * only valid value of type {@code Void}, methods such as {@code join}
  43  * always return {@code null} upon completion.
  44  *
  45  * <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
  46  * sort that sorts a given {@code long[]} array:
  47  *
  48  * <pre> {@code
  49  * static class SortTask extends RecursiveAction {
  50  *   final long[] array; final int lo, hi;
  51  *   SortTask(long[] array, int lo, int hi) {
  52  *     this.array = array; this.lo = lo; this.hi = hi;
  53  *   }
  54  *   SortTask(long[] array) { this(array, 0, array.length); }
  55  *   protected void compute() {
  56  *     if (hi - lo < THRESHOLD)
  57  *       sortSequentially(lo, hi);
  58  *     else {
  59  *       int mid = (lo + hi) >>> 1;
  60  *       invokeAll(new SortTask(array, lo, mid),
  61  *                 new SortTask(array, mid, hi));
  62  *       merge(lo, mid, hi);
  63  *     }
  64  *   }
  65  *   // implementation details follow:
  66  *   static final int THRESHOLD = 1000;
  67  *   void sortSequentially(int lo, int hi) {
  68  *     Arrays.sort(array, lo, hi);
  69  *   }
  70  *   void merge(int lo, int mid, int hi) {
  71  *     long[] buf = Arrays.copyOfRange(array, lo, mid);
  72  *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
  73  *       array[j] = (k == hi || buf[i] < array[k]) ?
  74  *         buf[i++] : array[k++];
  75  *   }
  76  * }}</pre>
  77  *
  78  * You could then sort {@code anArray} by creating {@code new
  79  * SortTask(anArray)} and invoking it in a ForkJoinPool.  As a more
  80  * concrete simple example, the following task increments each element
  81  * of an array:
  82  * <pre> {@code
  83  * class IncrementTask extends RecursiveAction {
  84  *   final long[] array; final int lo, hi;
  85  *   IncrementTask(long[] array, int lo, int hi) {
  86  *     this.array = array; this.lo = lo; this.hi = hi;
  87  *   }
  88  *   protected void compute() {
  89  *     if (hi - lo < THRESHOLD) {
  90  *       for (int i = lo; i < hi; ++i)
  91  *         array[i]++;
  92  *     }
  93  *     else {
  94  *       int mid = (lo + hi) >>> 1;
  95  *       invokeAll(new IncrementTask(array, lo, mid),
  96  *                 new IncrementTask(array, mid, hi));
  97  *     }
  98  *   }
  99  * }}</pre>
 100  *
 101  * <p>The following example illustrates some refinements and idioms
 102  * that may lead to better performance: RecursiveActions need not be
 103  * fully recursive, so long as they maintain the basic
 104  * divide-and-conquer approach. Here is a class that sums the squares
 105  * of each element of a double array, by subdividing out only the
 106  * right-hand-sides of repeated divisions by two, and keeping track of
 107  * them with a chain of {@code next} references. It uses a dynamic
 108  * threshold based on method {@code getSurplusQueuedTaskCount}, but
 109  * counterbalances potential excess partitioning by directly
 110  * performing leaf actions on unstolen tasks rather than further
 111  * subdividing.
 112  *
 113  * <pre> {@code
 114  * double sumOfSquares(ForkJoinPool pool, double[] array) {
 115  *   int n = array.length;
 116  *   Applyer a = new Applyer(array, 0, n, null);
 117  *   pool.invoke(a);
 118  *   return a.result;
 119  * }
 120  *
 121  * class Applyer extends RecursiveAction {
 122  *   final double[] array;
 123  *   final int lo, hi;
 124  *   double result;
 125  *   Applyer next; // keeps track of right-hand-side tasks
 126  *   Applyer(double[] array, int lo, int hi, Applyer next) {
 127  *     this.array = array; this.lo = lo; this.hi = hi;
 128  *     this.next = next;
 129  *   }
 130  *
 131  *   double atLeaf(int l, int h) {
 132  *     double sum = 0;
 133  *     for (int i = l; i < h; ++i) // perform leftmost base step
 134  *       sum += array[i] * array[i];
 135  *     return sum;
 136  *   }
 137  *
 138  *   protected void compute() {
 139  *     int l = lo;
 140  *     int h = hi;
 141  *     Applyer right = null;
 142  *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
 143  *       int mid = (l + h) >>> 1;
 144  *       right = new Applyer(array, mid, h, right);
 145  *       right.fork();
 146  *       h = mid;
 147  *     }
 148  *     double sum = atLeaf(l, h);
 149  *     while (right != null) {
 150  *       if (right.tryUnfork()) // directly calculate if not stolen
 151  *         sum += right.atLeaf(right.lo, right.hi);
 152  *       else {
 153  *         right.join();
 154  *         sum += right.result;
 155  *       }
 156  *       right = right.next;
 157  *     }
 158  *     result = sum;
 159  *   }
 160  * }}</pre>
 161  *
 162  * @since 1.7
 163  * @author Doug Lea
 164  */
 165 public abstract class RecursiveAction extends ForkJoinTask<Void> {
 166     private static final long serialVersionUID = 5232453952276485070L;
 167 
 168     /**
 169      * The main computation performed by this task.
 170      */
 171     protected abstract void compute();
 172 
 173     /**
 174      * Always returns {@code null}.
 175      *
 176      * @return {@code null} always
 177      */
 178     public final Void getRawResult() { return null; }
 179 
 180     /**
 181      * Requires null completion value.
 182      */
 183     protected final void setRawResult(Void mustBeNull) { }
 184 
 185     /**
 186      * Implements execution conventions for RecursiveActions.
 187      */
 188     protected final boolean exec() {
 189         compute();
 190         return true;
 191     }
 192 
 193 }