├── .java-version ├── .gitignore ├── project ├── plugins.sbt └── build.properties ├── src └── main │ ├── scala │ └── monix │ │ └── forkJoin │ │ ├── AdaptedForkJoinTask.scala │ │ ├── AdaptedForkJoinPool.scala │ │ ├── StandardWorkerThreadFactory.scala │ │ ├── ForkJoinExecutionContext.scala │ │ └── DynamicWorkerThreadFactory.scala │ └── java │ └── monix │ └── forkJoin │ ├── Unsafe.java │ ├── package-info.java │ ├── RecursiveTask.java │ ├── ForkJoinWorkerThread.java │ ├── RecursiveAction.java │ ├── TransferQueue.java │ ├── ThreadLocalRandom.java │ ├── LinkedTransferQueue.java │ └── ForkJoinTask.java ├── LICENSE.txt └── README.md /.java-version: -------------------------------------------------------------------------------- 1 | 1.8 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea* 2 | *.log 3 | .DS_Store 4 | target/ 5 | /.lib/ 6 | project/target/ 7 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += Classpaths.sbtPluginReleases 2 | 3 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") 4 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012-2017 by its authors. Some rights reserved. 3 | # See the project homepage at: https://github.com/monix/monix-forkjoin 4 | # 5 | # Licensed under the MIT License (the "License"); you may not use this 6 | # file except in compliance with the License. You may obtain a copy 7 | # of the License at: 8 | # 9 | # https://github.com/monix/monix-forkjoin/blob/master/LICENSE.txt 10 | # 11 | 12 | sbt.version=0.13.13 13 | -------------------------------------------------------------------------------- /src/main/scala/monix/forkJoin/AdaptedForkJoinTask.scala: -------------------------------------------------------------------------------- 1 | package monix.forkJoin 2 | 3 | final class AdaptedForkJoinTask(runnable: Runnable) 4 | extends ForkJoinTask[Unit] { 5 | 6 | def setRawResult(u: Unit): Unit = () 7 | def getRawResult(): Unit = () 8 | 9 | def exec(): Boolean = 10 | try { runnable.run(); true } catch { 11 | case anything: Throwable => 12 | val t = Thread.currentThread 13 | t.getUncaughtExceptionHandler match { 14 | case null => 15 | case some => some.uncaughtException(t, anything) 16 | } 17 | throw anything 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/scala/monix/forkJoin/AdaptedForkJoinPool.scala: -------------------------------------------------------------------------------- 1 | package monix.forkJoin 2 | 3 | import java.lang.Thread.UncaughtExceptionHandler 4 | import monix.forkJoin.ForkJoinPool.ForkJoinWorkerThreadFactory 5 | 6 | final class AdaptedForkJoinPool( 7 | parallelism: Int, 8 | factory: ForkJoinWorkerThreadFactory, 9 | handler: UncaughtExceptionHandler, 10 | asyncMode: Boolean) 11 | extends ForkJoinPool(parallelism, factory, handler, asyncMode) { 12 | 13 | override def execute(runnable: Runnable): Unit = { 14 | val fjt: ForkJoinTask[_] = runnable match { 15 | case t: ForkJoinTask[_] => t 16 | case r => new AdaptedForkJoinTask(r) 17 | } 18 | 19 | Thread.currentThread match { 20 | case fjw: ForkJoinWorkerThread if fjw.getPool eq this => fjt.fork() 21 | case _ => super.execute(fjt) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/monix/forkJoin/StandardWorkerThreadFactory.scala: -------------------------------------------------------------------------------- 1 | package monix.forkJoin 2 | 3 | import java.lang.Thread.UncaughtExceptionHandler 4 | import java.util.concurrent.ThreadFactory 5 | import monix.forkJoin.ForkJoinPool.ForkJoinWorkerThreadFactory 6 | 7 | final class StandardWorkerThreadFactory( 8 | prefix: String, 9 | reporter: Throwable => Unit, 10 | daemonic: Boolean) 11 | extends ThreadFactory with ForkJoinWorkerThreadFactory { 12 | 13 | def wire[T <: Thread](thread: T): T = { 14 | thread.setDaemon(daemonic) 15 | thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler { 16 | override def uncaughtException(t: Thread, e: Throwable): Unit = 17 | reporter(e) 18 | }) 19 | 20 | thread.setName(prefix + "-" + thread.getId) 21 | thread 22 | } 23 | 24 | override def newThread(r: Runnable): Thread = 25 | wire(new Thread(r)) 26 | 27 | override def newThread(pool: ForkJoinPool): ForkJoinWorkerThread = 28 | wire(new ForkJoinWorkerThread(pool) {}) 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/monix/forkJoin/Unsafe.java: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package monix.forkJoin; 10 | 11 | import java.lang.reflect.Field; 12 | 13 | public final class Unsafe { 14 | public final static sun.misc.Unsafe instance; 15 | static { 16 | try { 17 | sun.misc.Unsafe found = null; 18 | for(Field field : sun.misc.Unsafe.class.getDeclaredFields()) { 19 | if (field.getType() == sun.misc.Unsafe.class) { 20 | field.setAccessible(true); 21 | found = (sun.misc.Unsafe) field.get(null); 22 | break; 23 | } 24 | } 25 | if (found == null) throw new IllegalStateException("Can't find instance of sun.misc.Unsafe"); 26 | else instance = found; 27 | } catch(Throwable t) { 28 | throw new ExceptionInInitializerError(t); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/monix/forkJoin/package-info.java: -------------------------------------------------------------------------------- 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/publicdomain/zero/1.0/ 5 | */ 6 | 7 | 8 | /** 9 | * Preview versions of classes targeted for Java 7. Includes a 10 | * fine-grained parallel computation framework: ForkJoinTasks and 11 | * their related support classes provide a very efficient basis for 12 | * obtaining platform-independent parallel speed-ups of 13 | * computation-intensive operations. They are not a full substitute 14 | * for the kinds of arbitrary processing supported by Executors or 15 | * Threads. However, when applicable, they typically provide 16 | * significantly greater performance on multiprocessor platforms. 17 | * 18 | *
Candidates for fork/join processing mainly include those that 19 | * can be expressed using parallel divide-and-conquer techniques: To 20 | * solve a problem, break it in two (or more) parts, and then solve 21 | * those parts in parallel, continuing on in this way until the 22 | * problem is too small to be broken up, so is solved directly. The 23 | * underlying work-stealing framework makes subtasks 24 | * available to other threads (normally one per CPU), that help 25 | * complete the tasks. In general, the most efficient ForkJoinTasks 26 | * are those that directly implement this algorithmic design pattern. 27 | */ 28 | package monix.forkJoin; 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Scala is licensed under the BSD 3-Clause License. 2 | Scala License 3 | 4 | Copyright (c) 2002-2016 EPFL 5 | Copyright (c) 2011-2016 Lightbend, Inc. 6 | Copyright (c) 2016 Alexandru Nedelcu 7 | 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without modification, 11 | are permitted provided that the following conditions are met: 12 | 13 | - Redistributions of source code must retain the above copyright notice, 14 | this list of conditions and the following disclaimer. 15 | - Redistributions in binary form must reproduce the above copyright notice, 16 | this list of conditions and the following disclaimer in the documentation 17 | and/or other materials provided with the distribution. 18 | - Neither the name of the EPFL nor the names of its contributors may be 19 | used to endorse or promote products derived from this software without 20 | specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY 23 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /src/main/scala/monix/forkJoin/ForkJoinExecutionContext.scala: -------------------------------------------------------------------------------- 1 | package monix.forkJoin 2 | 3 | import java.lang.Thread.UncaughtExceptionHandler 4 | import scala.concurrent.ExecutionContext 5 | 6 | object ForkJoinExecutionContext { 7 | /** Creates a Scala `ExecutionContext` powered by a JSR-166 8 | * `ForkJoinPool` implementation with the ability to add threads 9 | * in case blocking operations happen. 10 | * 11 | * The resulting instance collaborates with Scala's `BlockContext` 12 | * and has the same behavior as Scala's own `global`. 13 | */ 14 | def createDynamic( 15 | parallelism: Int, 16 | maxThreads: Int, 17 | name: String = "forkJoin-dynamic", 18 | daemonic: Boolean = true, 19 | reporter: Throwable => Unit = _.printStackTrace()): ExecutionContext = { 20 | 21 | val exceptionHandler = new UncaughtExceptionHandler { 22 | def uncaughtException(t: Thread, e: Throwable) = 23 | reporter(e) 24 | } 25 | 26 | val pool = new AdaptedForkJoinPool( 27 | parallelism, 28 | new DynamicWorkerThreadFactory(name, maxThreads, exceptionHandler, daemonic), 29 | exceptionHandler, 30 | asyncMode = true 31 | ) 32 | 33 | ExecutionContext.fromExecutor(pool, reporter) 34 | } 35 | 36 | /** Creates a Scala `ExecutionContext` powered by a JSR-166 37 | * `ForkJoinPool` implementation. 38 | */ 39 | def createStandard( 40 | parallelism: Int, 41 | name: String = "forkJoin-standard", 42 | daemonic: Boolean = true, 43 | reporter: Throwable => Unit = _.printStackTrace()): ExecutionContext = { 44 | 45 | val exceptionHandler = new UncaughtExceptionHandler { 46 | def uncaughtException(t: Thread, e: Throwable) = 47 | reporter(e) 48 | } 49 | 50 | val pool = new AdaptedForkJoinPool( 51 | parallelism, 52 | new StandardWorkerThreadFactory(name, reporter, daemonic), 53 | exceptionHandler, 54 | asyncMode = true 55 | ) 56 | 57 | ExecutionContext.fromExecutor(pool, reporter) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/monix/forkJoin/RecursiveTask.java: -------------------------------------------------------------------------------- 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/publicdomain/zero/1.0/ 5 | */ 6 | 7 | package monix.forkJoin; 8 | 9 | /** 10 | * A recursive result-bearing {@link ForkJoinTask}. 11 | * 12 | *
For a classic example, here is a task computing Fibonacci numbers: 13 | * 14 | *
{@code
15 | * class Fibonacci extends RecursiveTask {
16 | * final int n;
17 | * Fibonacci(int n) { this.n = n; }
18 | * Integer compute() {
19 | * if (n <= 1)
20 | * return n;
21 | * Fibonacci f1 = new Fibonacci(n - 1);
22 | * f1.fork();
23 | * Fibonacci f2 = new Fibonacci(n - 2);
24 | * return f2.compute() + f1.join();
25 | * }
26 | * }}
27 | *
28 | * However, besides being a dumb way to compute Fibonacci functions
29 | * (there is a simple fast linear algorithm that you'd use in
30 | * practice), this is likely to perform poorly because the smallest
31 | * subtasks are too small to be worthwhile splitting up. Instead, as
32 | * is the case for nearly all fork/join applications, you'd pick some
33 | * minimum granularity size (for example 10 here) for which you always
34 | * sequentially solve rather than subdividing.
35 | *
36 | * @since 1.7
37 | * @author Doug Lea
38 | */
39 | public abstract class RecursiveTaskSample Usages. Here is a simple but complete ForkJoin 17 | * sort that sorts a given {@code long[]} array: 18 | * 19 | *
{@code
20 | * static class SortTask extends RecursiveAction {
21 | * final long[] array; final int lo, hi;
22 | * SortTask(long[] array, int lo, int hi) {
23 | * this.array = array; this.lo = lo; this.hi = hi;
24 | * }
25 | * SortTask(long[] array) { this(array, 0, array.length); }
26 | * protected void compute() {
27 | * if (hi - lo < THRESHOLD)
28 | * sortSequentially(lo, hi);
29 | * else {
30 | * int mid = (lo + hi) >>> 1;
31 | * invokeAll(new SortTask(array, lo, mid),
32 | * new SortTask(array, mid, hi));
33 | * merge(lo, mid, hi);
34 | * }
35 | * }
36 | * // 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 | * }}
48 | *
49 | * You could then sort {@code anArray} by creating {@code new
50 | * 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 | * {@code
54 | * class IncrementTask extends RecursiveAction {
55 | * final long[] array; final int lo, hi;
56 | * IncrementTask(long[] array, int lo, int hi) {
57 | * this.array = array; this.lo = lo; this.hi = hi;
58 | * }
59 | * protected void compute() {
60 | * if (hi - lo < THRESHOLD) {
61 | * for (int i = lo; i < hi; ++i)
62 | * array[i]++;
63 | * }
64 | * else {
65 | * int mid = (lo + hi) >>> 1;
66 | * invokeAll(new IncrementTask(array, lo, mid),
67 | * new IncrementTask(array, mid, hi));
68 | * }
69 | * }
70 | * }}
71 | *
72 | * 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 | * them with a chain of {@code next} references. It uses a dynamic 79 | * threshold based on method {@code getSurplusQueuedTaskCount}, but 80 | * counterbalances potential excess partitioning by directly 81 | * performing leaf actions on unstolen tasks rather than further 82 | * subdividing. 83 | * 84 | *
{@code
85 | * double sumOfSquares(ForkJoinPool pool, double[] array) {
86 | * int n = array.length;
87 | * Applyer a = new Applyer(array, 0, n, null);
88 | * pool.invoke(a);
89 | * return a.result;
90 | * }
91 | *
92 | * class Applyer extends RecursiveAction {
93 | * final double[] array;
94 | * final int lo, hi;
95 | * double result;
96 | * Applyer next; // keeps track of right-hand-side tasks
97 | * Applyer(double[] array, int lo, int hi, Applyer next) {
98 | * this.array = array; this.lo = lo; this.hi = hi;
99 | * this.next = next;
100 | * }
101 | *
102 | * double atLeaf(int l, int h) {
103 | * double sum = 0;
104 | * for (int i = l; i < h; ++i) // perform leftmost base step
105 | * 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 | * while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
114 | * int mid = (l + h) >>> 1;
115 | * right = new Applyer(array, mid, h, right);
116 | * 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 | * right.join();
125 | * sum += right.result;
126 | * }
127 | * right = right.next;
128 | * }
129 | * result = sum;
130 | * }
131 | * }}
132 | *
133 | * @since 1.7
134 | * @author Doug Lea
135 | */
136 | public abstract class RecursiveAction extends ForkJoinTaskLike other blocking queues, a {@code TransferQueue} may be 26 | * capacity bounded. If so, an attempted transfer operation may 27 | * initially block waiting for available space, and/or subsequently 28 | * block waiting for reception by a consumer. Note that in a queue 29 | * with zero capacity, such as {@link SynchronousQueue}, {@code put} 30 | * and {@code transfer} are effectively synonymous. 31 | * 32 | *
This interface is a member of the
33 | *
34 | * Java Collections Framework.
35 | *
36 | * @since 1.7
37 | * @author Doug Lea
38 | * @param More precisely, transfers the specified element immediately
45 | * if there exists a consumer already waiting to receive it (in
46 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
47 | * otherwise returning {@code false} without enqueuing the element.
48 | *
49 | * @param e the element to transfer
50 | * @return {@code true} if the element was transferred, else
51 | * {@code false}
52 | * @throws ClassCastException if the class of the specified element
53 | * prevents it from being added to this queue
54 | * @throws NullPointerException if the specified element is null
55 | * @throws IllegalArgumentException if some property of the specified
56 | * element prevents it from being added to this queue
57 | */
58 | boolean tryTransfer(E e);
59 |
60 | /**
61 | * Transfers the element to a consumer, waiting if necessary to do so.
62 | *
63 | * More precisely, transfers the specified element immediately
64 | * if there exists a consumer already waiting to receive it (in
65 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
66 | * else waits until the element is received by a consumer.
67 | *
68 | * @param e the element to transfer
69 | * @throws InterruptedException if interrupted while waiting,
70 | * in which case the element is not left enqueued
71 | * @throws ClassCastException if the class of the specified element
72 | * prevents it from being added to this queue
73 | * @throws NullPointerException if the specified element is null
74 | * @throws IllegalArgumentException if some property of the specified
75 | * element prevents it from being added to this queue
76 | */
77 | void transfer(E e) throws InterruptedException;
78 |
79 | /**
80 | * Transfers the element to a consumer if it is possible to do so
81 | * before the timeout elapses.
82 | *
83 | * More precisely, transfers the specified element immediately
84 | * if there exists a consumer already waiting to receive it (in
85 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
86 | * else waits until the element is received by a consumer,
87 | * returning {@code false} if the specified wait time elapses
88 | * before the element can be transferred.
89 | *
90 | * @param e the element to transfer
91 | * @param timeout how long to wait before giving up, in units of
92 | * {@code unit}
93 | * @param unit a {@code TimeUnit} determining how to interpret the
94 | * {@code timeout} parameter
95 | * @return {@code true} if successful, or {@code false} if
96 | * the specified waiting time elapses before completion,
97 | * in which case the element is not left enqueued
98 | * @throws InterruptedException if interrupted while waiting,
99 | * in which case the element is not left enqueued
100 | * @throws ClassCastException if the class of the specified element
101 | * prevents it from being added to this queue
102 | * @throws NullPointerException if the specified element is null
103 | * @throws IllegalArgumentException if some property of the specified
104 | * element prevents it from being added to this queue
105 | */
106 | boolean tryTransfer(E e, long timeout, TimeUnit unit)
107 | throws InterruptedException;
108 |
109 | /**
110 | * Returns {@code true} if there is at least one consumer waiting
111 | * to receive an element via {@link #take} or
112 | * timed {@link #poll(long,TimeUnit) poll}.
113 | * The return value represents a momentary state of affairs.
114 | *
115 | * @return {@code true} if there is at least one waiting consumer
116 | */
117 | boolean hasWaitingConsumer();
118 |
119 | /**
120 | * Returns an estimate of the number of consumers waiting to
121 | * receive elements via {@link #take} or timed
122 | * {@link #poll(long,TimeUnit) poll}. The return value is an
123 | * approximation of a momentary state of affairs, that may be
124 | * inaccurate if consumers have completed or given up waiting.
125 | * The value may be useful for monitoring and heuristics, but
126 | * not for synchronization control. Implementations of this
127 | * method are likely to be noticeably slower than those for
128 | * {@link #hasWaitingConsumer}.
129 | *
130 | * @return the number of consumers waiting to receive elements
131 | */
132 | int getWaitingConsumerCount();
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/monix/forkJoin/ThreadLocalRandom.java:
--------------------------------------------------------------------------------
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/publicdomain/zero/1.0/
5 | */
6 |
7 | package monix.forkJoin;
8 |
9 | import java.util.Random;
10 |
11 | /**
12 | * A random number generator isolated to the current thread. Like the
13 | * global {@link java.util.Random} generator used by the {@link
14 | * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
15 | * with an internally generated seed that may not otherwise be
16 | * modified. When applicable, use of {@code ThreadLocalRandom} rather
17 | * than shared {@code Random} objects in concurrent programs will
18 | * typically encounter much less overhead and contention. Use of
19 | * {@code ThreadLocalRandom} is particularly appropriate when multiple
20 | * tasks (for example, each a {@link ForkJoinTask}) use random numbers
21 | * in parallel in thread pools.
22 | *
23 | * Usages of this class should typically be of the form:
24 | * {@code ThreadLocalRandom.current().nextX(...)} (where
25 | * {@code X} is {@code Int}, {@code Long}, etc).
26 | * When all usages are of this form, it is never possible to
27 | * accidentally share a {@code ThreadLocalRandom} across multiple threads.
28 | *
29 | * This class also provides additional commonly used bounded random
30 | * generation methods.
31 | *
32 | * @since 1.7
33 | * @author Doug Lea
34 | */
35 | public class ThreadLocalRandom extends Random {
36 | // same constants as Random, but must be redeclared because private
37 | private static final long multiplier = 0x5DEECE66DL;
38 | private static final long addend = 0xBL;
39 | private static final long mask = (1L << 48) - 1;
40 |
41 | /**
42 | * The random seed. We can't use super.seed.
43 | */
44 | private long rnd;
45 |
46 | /**
47 | * Initialization flag to permit calls to setSeed to succeed only
48 | * while executing the Random constructor. We can't allow others
49 | * since it would cause setting seed in one part of a program to
50 | * unintentionally impact other usages by the thread.
51 | */
52 | boolean initialized;
53 |
54 | // Padding to help avoid memory contention among seed updates in
55 | // different TLRs in the common case that they are located near
56 | // each other.
57 | private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
58 |
59 | /**
60 | * The actual ThreadLocal
61 | */
62 | private static final ThreadLocal Beware that, unlike in most collections, the {@code size} method
26 | * is NOT a constant-time operation. Because of the
27 | * asynchronous nature of these queues, determining the current number
28 | * of elements requires a traversal of the elements, and so may report
29 | * inaccurate results if this collection is modified during traversal.
30 | * Additionally, the bulk operations {@code addAll},
31 | * {@code removeAll}, {@code retainAll}, {@code containsAll},
32 | * {@code equals}, and {@code toArray} are not guaranteed
33 | * to be performed atomically. For example, an iterator operating
34 | * concurrently with an {@code addAll} operation might view only some
35 | * of the added elements.
36 | *
37 | * This class and its iterator implement all of the
38 | * optional methods of the {@link Collection} and {@link
39 | * Iterator} interfaces.
40 | *
41 | * Memory consistency effects: As with other concurrent
42 | * collections, actions in a thread prior to placing an object into a
43 | * {@code LinkedTransferQueue}
44 | * happen-before
45 | * actions subsequent to the access or removal of that element from
46 | * the {@code LinkedTransferQueue} in another thread.
47 | *
48 | * This class is a member of the
49 | *
50 | * Java Collections Framework.
51 | *
52 | * @since 1.7
53 | * @author Doug Lea
54 | * @param More precisely, transfers the specified element immediately
1057 | * if there exists a consumer already waiting to receive it (in
1058 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
1059 | * otherwise returning {@code false} without enqueuing the element.
1060 | *
1061 | * @throws NullPointerException if the specified element is null
1062 | */
1063 | public boolean tryTransfer(E e) {
1064 | return xfer(e, true, NOW, 0) == null;
1065 | }
1066 |
1067 | /**
1068 | * Transfers the element to a consumer, waiting if necessary to do so.
1069 | *
1070 | * More precisely, transfers the specified element immediately
1071 | * if there exists a consumer already waiting to receive it (in
1072 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
1073 | * else inserts the specified element at the tail of this queue
1074 | * and waits until the element is received by a consumer.
1075 | *
1076 | * @throws NullPointerException if the specified element is null
1077 | */
1078 | public void transfer(E e) throws InterruptedException {
1079 | if (xfer(e, true, SYNC, 0) != null) {
1080 | Thread.interrupted(); // failure possible only due to interrupt
1081 | throw new InterruptedException();
1082 | }
1083 | }
1084 |
1085 | /**
1086 | * Transfers the element to a consumer if it is possible to do so
1087 | * before the timeout elapses.
1088 | *
1089 | * More precisely, transfers the specified element immediately
1090 | * if there exists a consumer already waiting to receive it (in
1091 | * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
1092 | * else inserts the specified element at the tail of this queue
1093 | * and waits until the element is received by a consumer,
1094 | * returning {@code false} if the specified wait time elapses
1095 | * before the element can be transferred.
1096 | *
1097 | * @throws NullPointerException if the specified element is null
1098 | */
1099 | public boolean tryTransfer(E e, long timeout, TimeUnit unit)
1100 | throws InterruptedException {
1101 | if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null)
1102 | return true;
1103 | if (!Thread.interrupted())
1104 | return false;
1105 | throw new InterruptedException();
1106 | }
1107 |
1108 | public E take() throws InterruptedException {
1109 | E e = xfer(null, false, SYNC, 0);
1110 | if (e != null)
1111 | return e;
1112 | Thread.interrupted();
1113 | throw new InterruptedException();
1114 | }
1115 |
1116 | public E poll(long timeout, TimeUnit unit) throws InterruptedException {
1117 | E e = xfer(null, false, TIMED, unit.toNanos(timeout));
1118 | if (e != null || !Thread.interrupted())
1119 | return e;
1120 | throw new InterruptedException();
1121 | }
1122 |
1123 | public E poll() {
1124 | return xfer(null, false, NOW, 0);
1125 | }
1126 |
1127 | /**
1128 | * @throws NullPointerException {@inheritDoc}
1129 | * @throws IllegalArgumentException {@inheritDoc}
1130 | */
1131 | public int drainTo(Collection super E> c) {
1132 | if (c == null)
1133 | throw new NullPointerException();
1134 | if (c == this)
1135 | throw new IllegalArgumentException();
1136 | int n = 0;
1137 | for (E e; (e = poll()) != null;) {
1138 | c.add(e);
1139 | ++n;
1140 | }
1141 | return n;
1142 | }
1143 |
1144 | /**
1145 | * @throws NullPointerException {@inheritDoc}
1146 | * @throws IllegalArgumentException {@inheritDoc}
1147 | */
1148 | public int drainTo(Collection super E> c, int maxElements) {
1149 | if (c == null)
1150 | throw new NullPointerException();
1151 | if (c == this)
1152 | throw new IllegalArgumentException();
1153 | int n = 0;
1154 | for (E e; n < maxElements && (e = poll()) != null;) {
1155 | c.add(e);
1156 | ++n;
1157 | }
1158 | return n;
1159 | }
1160 |
1161 | /**
1162 | * Returns an iterator over the elements in this queue in proper sequence.
1163 | * The elements will be returned in order from first (head) to last (tail).
1164 | *
1165 | * The returned iterator is a "weakly consistent" iterator that
1166 | * will never throw {@link java.util.ConcurrentModificationException
1167 | * ConcurrentModificationException}, and guarantees to traverse
1168 | * elements as they existed upon construction of the iterator, and
1169 | * may (but is not guaranteed to) reflect any modifications
1170 | * subsequent to construction.
1171 | *
1172 | * @return an iterator over the elements in this queue in proper sequence
1173 | */
1174 | public Iterator Beware that, unlike in most collections, this method is
1205 | * NOT a constant-time operation. Because of the
1206 | * asynchronous nature of these queues, determining the current
1207 | * number of elements requires an O(n) traversal.
1208 | *
1209 | * @return the number of elements in this queue
1210 | */
1211 | public int size() {
1212 | return countOfMode(true);
1213 | }
1214 |
1215 | public int getWaitingConsumerCount() {
1216 | return countOfMode(false);
1217 | }
1218 |
1219 | /**
1220 | * Removes a single instance of the specified element from this queue,
1221 | * if it is present. More formally, removes an element {@code e} such
1222 | * that {@code o.equals(e)}, if this queue contains one or more such
1223 | * elements.
1224 | * Returns {@code true} if this queue contained the specified element
1225 | * (or equivalently, if this queue changed as a result of the call).
1226 | *
1227 | * @param o element to be removed from this queue, if present
1228 | * @return {@code true} if this queue changed as a result of the call
1229 | */
1230 | public boolean remove(Object o) {
1231 | return findAndRemove(o);
1232 | }
1233 |
1234 | /**
1235 | * Returns {@code true} if this queue contains the specified element.
1236 | * More formally, returns {@code true} if and only if this queue contains
1237 | * at least one element {@code e} such that {@code o.equals(e)}.
1238 | *
1239 | * @param o object to be checked for containment in this queue
1240 | * @return {@code true} if this queue contains the specified element
1241 | */
1242 | public boolean contains(Object o) {
1243 | if (o == null) return false;
1244 | for (Node p = head; p != null; p = succ(p)) {
1245 | Object item = p.item;
1246 | if (p.isData) {
1247 | if (item != null && item != p && o.equals(item))
1248 | return true;
1249 | }
1250 | else if (item == null)
1251 | break;
1252 | }
1253 | return false;
1254 | }
1255 |
1256 | /**
1257 | * Always returns {@code Integer.MAX_VALUE} because a
1258 | * {@code LinkedTransferQueue} is not capacity constrained.
1259 | *
1260 | * @return {@code Integer.MAX_VALUE} (as specified by
1261 | * {@link java.util.concurrent.BlockingQueue#remainingCapacity()
1262 | * BlockingQueue.remainingCapacity})
1263 | */
1264 | public int remainingCapacity() {
1265 | return Integer.MAX_VALUE;
1266 | }
1267 |
1268 | /**
1269 | * Saves the state to a stream (that is, serializes it).
1270 | *
1271 | * @serialData All of the elements (each an {@code E}) in
1272 | * the proper order, followed by a null
1273 | * @param s the stream
1274 | */
1275 | private void writeObject(java.io.ObjectOutputStream s)
1276 | throws java.io.IOException {
1277 | s.defaultWriteObject();
1278 | for (E e : this)
1279 | s.writeObject(e);
1280 | // Use trailing null as sentinel
1281 | s.writeObject(null);
1282 | }
1283 |
1284 | /**
1285 | * Reconstitutes the Queue instance from a stream (that is,
1286 | * deserializes it).
1287 | *
1288 | * @param s the stream
1289 | */
1290 | private void readObject(java.io.ObjectInputStream s)
1291 | throws java.io.IOException, ClassNotFoundException {
1292 | s.defaultReadObject();
1293 | for (;;) {
1294 | @SuppressWarnings("unchecked")
1295 | E item = (E) s.readObject();
1296 | if (item == null)
1297 | break;
1298 | else
1299 | offer(item);
1300 | }
1301 | }
1302 |
1303 | // Unsafe mechanics
1304 |
1305 | private static final sun.misc.Unsafe UNSAFE;
1306 | private static final long headOffset;
1307 | private static final long tailOffset;
1308 | private static final long sweepVotesOffset;
1309 | static {
1310 | try {
1311 | UNSAFE = getUnsafe();
1312 | Class> k = LinkedTransferQueue.class;
1313 | headOffset = UNSAFE.objectFieldOffset
1314 | (k.getDeclaredField("head"));
1315 | tailOffset = UNSAFE.objectFieldOffset
1316 | (k.getDeclaredField("tail"));
1317 | sweepVotesOffset = UNSAFE.objectFieldOffset
1318 | (k.getDeclaredField("sweepVotes"));
1319 | } catch (Exception e) {
1320 | throw new Error(e);
1321 | }
1322 | }
1323 |
1324 | /**
1325 | * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
1326 | * Replace with a simple call to Unsafe.getUnsafe when integrating
1327 | * into a jdk.
1328 | *
1329 | * @return a sun.misc.Unsafe
1330 | */
1331 | static sun.misc.Unsafe getUnsafe() {
1332 | return monix.forkJoin.Unsafe.instance;
1333 | }
1334 |
1335 | }
1336 |
--------------------------------------------------------------------------------
/src/main/java/monix/forkJoin/ForkJoinTask.java:
--------------------------------------------------------------------------------
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/publicdomain/zero/1.0/
5 | */
6 |
7 | package monix.forkJoin;
8 |
9 | import java.io.Serializable;
10 | import java.util.Collection;
11 | import java.util.List;
12 | import java.util.RandomAccess;
13 | import java.lang.ref.WeakReference;
14 | import java.lang.ref.ReferenceQueue;
15 | import java.util.concurrent.Callable;
16 | import java.util.concurrent.CancellationException;
17 | import java.util.concurrent.ExecutionException;
18 | import java.util.concurrent.Future;
19 | import java.util.concurrent.RejectedExecutionException;
20 | import java.util.concurrent.RunnableFuture;
21 | import java.util.concurrent.TimeUnit;
22 | import java.util.concurrent.TimeoutException;
23 | import java.util.concurrent.locks.ReentrantLock;
24 | import java.lang.reflect.Constructor;
25 |
26 | /**
27 | * Abstract base class for tasks that run within a {@link ForkJoinPool}.
28 | * A {@code ForkJoinTask} is a thread-like entity that is much
29 | * lighter weight than a normal thread. Huge numbers of tasks and
30 | * subtasks may be hosted by a small number of actual threads in a
31 | * ForkJoinPool, at the price of some usage limitations.
32 | *
33 | * A "main" {@code ForkJoinTask} begins execution when it is
34 | * explicitly submitted to a {@link ForkJoinPool}, or, if not already
35 | * engaged in a ForkJoin computation, commenced in the {@link
36 | * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
37 | * related methods. Once started, it will usually in turn start other
38 | * subtasks. As indicated by the name of this class, many programs
39 | * using {@code ForkJoinTask} employ only methods {@link #fork} and
40 | * {@link #join}, or derivatives such as {@link
41 | * #invokeAll(ForkJoinTask...) invokeAll}. However, this class also
42 | * provides a number of other methods that can come into play in
43 | * advanced usages, as well as extension mechanics that allow support
44 | * of new forms of fork/join processing.
45 | *
46 | * A {@code ForkJoinTask} is a lightweight form of {@link Future}.
47 | * The efficiency of {@code ForkJoinTask}s stems from a set of
48 | * restrictions (that are only partially statically enforceable)
49 | * reflecting their main use as computational tasks calculating pure
50 | * functions or operating on purely isolated objects. The primary
51 | * coordination mechanisms are {@link #fork}, that arranges
52 | * asynchronous execution, and {@link #join}, that doesn't proceed
53 | * until the task's result has been computed. Computations should
54 | * ideally avoid {@code synchronized} methods or blocks, and should
55 | * minimize other blocking synchronization apart from joining other
56 | * tasks or using synchronizers such as Phasers that are advertised to
57 | * cooperate with fork/join scheduling. Subdividable tasks should also
58 | * not perform blocking I/O, and should ideally access variables that
59 | * are completely independent of those accessed by other running
60 | * tasks. These guidelines are loosely enforced by not permitting
61 | * checked exceptions such as {@code IOExceptions} to be
62 | * thrown. However, computations may still encounter unchecked
63 | * exceptions, that are rethrown to callers attempting to join
64 | * them. These exceptions may additionally include {@link
65 | * RejectedExecutionException} stemming from internal resource
66 | * exhaustion, such as failure to allocate internal task
67 | * queues. Rethrown exceptions behave in the same way as regular
68 | * exceptions, but, when possible, contain stack traces (as displayed
69 | * for example using {@code ex.printStackTrace()}) of both the thread
70 | * that initiated the computation as well as the thread actually
71 | * encountering the exception; minimally only the latter.
72 | *
73 | * It is possible to define and use ForkJoinTasks that may block,
74 | * but doing do requires three further considerations: (1) Completion
75 | * of few if any other tasks should be dependent on a task
76 | * that blocks on external synchronization or I/O. Event-style async
77 | * tasks that are never joined (for example, those subclassing {@link
78 | * CountedCompleter}) often fall into this category. (2) To minimize
79 | * resource impact, tasks should be small; ideally performing only the
80 | * (possibly) blocking action. (3) Unless the {@link
81 | * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
82 | * blocked tasks is known to be less than the pool's {@link
83 | * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
84 | * enough threads will be available to ensure progress or good
85 | * performance.
86 | *
87 | * The primary method for awaiting completion and extracting
88 | * results of a task is {@link #join}, but there are several variants:
89 | * The {@link Future#get} methods support interruptible and/or timed
90 | * waits for completion and report results using {@code Future}
91 | * conventions. Method {@link #invoke} is semantically
92 | * equivalent to {@code fork(); join()} but always attempts to begin
93 | * execution in the current thread. The "quiet" forms of
94 | * these methods do not extract results or report exceptions. These
95 | * may be useful when a set of tasks are being executed, and you need
96 | * to delay processing of results or exceptions until all complete.
97 | * Method {@code invokeAll} (available in multiple versions)
98 | * performs the most common form of parallel invocation: forking a set
99 | * of tasks and joining them all.
100 | *
101 | * In the most typical usages, a fork-join pair act like a call
102 | * (fork) and return (join) from a parallel recursive function. As is
103 | * the case with other forms of recursive calls, returns (joins)
104 | * should be performed innermost-first. For example, {@code a.fork();
105 | * b.fork(); b.join(); a.join();} is likely to be substantially more
106 | * efficient than joining {@code a} before {@code b}.
107 | *
108 | * The execution status of tasks may be queried at several levels
109 | * of detail: {@link #isDone} is true if a task completed in any way
110 | * (including the case where a task was cancelled without executing);
111 | * {@link #isCompletedNormally} is true if a task completed without
112 | * cancellation or encountering an exception; {@link #isCancelled} is
113 | * true if the task was cancelled (in which case {@link #getException}
114 | * returns a {@link java.util.concurrent.CancellationException}); and
115 | * {@link #isCompletedAbnormally} is true if a task was either
116 | * cancelled or encountered an exception, in which case {@link
117 | * #getException} will return either the encountered exception or
118 | * {@link java.util.concurrent.CancellationException}.
119 | *
120 | * The ForkJoinTask class is not usually directly subclassed.
121 | * Instead, you subclass one of the abstract classes that support a
122 | * particular style of fork/join processing, typically {@link
123 | * RecursiveAction} for most computations that do not return results,
124 | * {@link RecursiveTask} for those that do, and {@link
125 | * CountedCompleter} for those in which completed actions trigger
126 | * other actions. Normally, a concrete ForkJoinTask subclass declares
127 | * fields comprising its parameters, established in a constructor, and
128 | * then defines a {@code compute} method that somehow uses the control
129 | * methods supplied by this base class.
130 | *
131 | * Method {@link #join} and its variants are appropriate for use
132 | * only when completion dependencies are acyclic; that is, the
133 | * parallel computation can be described as a directed acyclic graph
134 | * (DAG). Otherwise, executions may encounter a form of deadlock as
135 | * tasks cyclically wait for each other. However, this framework
136 | * supports other methods and techniques (for example the use of
137 | * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
138 | * may be of use in constructing custom subclasses for problems that
139 | * are not statically structured as DAGs. To support such usages a
140 | * ForkJoinTask may be atomically tagged with a {@code short}
141 | * value using {@link #setForkJoinTaskTag} or {@link
142 | * #compareAndSetForkJoinTaskTag} and checked using {@link
143 | * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
144 | * these {@code protected} methods or tags for any purpose, but they
145 | * may be of use in the construction of specialized subclasses. For
146 | * example, parallel graph traversals can use the supplied methods to
147 | * avoid revisiting nodes/tasks that have already been processed.
148 | * (Method names for tagging are bulky in part to encourage definition
149 | * of methods that reflect their usage patterns.)
150 | *
151 | * Most base support methods are {@code final}, to prevent
152 | * overriding of implementations that are intrinsically tied to the
153 | * underlying lightweight task scheduling framework. Developers
154 | * creating new basic styles of fork/join processing should minimally
155 | * implement {@code protected} methods {@link #exec}, {@link
156 | * #setRawResult}, and {@link #getRawResult}, while also introducing
157 | * an abstract computational method that can be implemented in its
158 | * subclasses, possibly relying on other {@code protected} methods
159 | * provided by this class.
160 | *
161 | * ForkJoinTasks should perform relatively small amounts of
162 | * computation. Large tasks should be split into smaller subtasks,
163 | * usually via recursive decomposition. As a very rough rule of thumb,
164 | * a task should perform more than 100 and less than 10000 basic
165 | * computational steps, and should avoid indefinite looping. If tasks
166 | * are too big, then parallelism cannot improve throughput. If too
167 | * small, then memory and internal task maintenance overhead may
168 | * overwhelm processing.
169 | *
170 | * This class provides {@code adapt} methods for {@link Runnable}
171 | * and {@link Callable}, that may be of use when mixing execution of
172 | * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
173 | * of this form, consider using a pool constructed in asyncMode.
174 | *
175 | * ForkJoinTasks are {@code Serializable}, which enables them to be
176 | * used in extensions such as remote execution frameworks. It is
177 | * sensible to serialize tasks only before or after, but not during,
178 | * execution. Serialization is not relied on during execution itself.
179 | *
180 | * @since 1.7
181 | * @author Doug Lea
182 | */
183 | public abstract class ForkJoinTask