Download presentation
Presentation is loading. Please wait.
1
ForkJoin New in Java 7 Apr 5, 2012
2
Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; The first thing you need to do is to import some classes. These are built into Java 7, but are also available as a separate download for Java 6. 2
3
Incrementor II package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Incrementor extends RecursiveTask<Integer> { } Next you need to create a class that extends RecursiveTask. A RecursiveTask is like a Thread, but you can retrieve a value from it after it finishes. Supply a type parameter (Integer, in this example) to specify the kind of value you want. 3
4
Incrementor III package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Incrementor extends RecursiveTask<Integer> { public static ForkJoinPool fjPool = new ForkJoinPool(); } Create a ForkJoinPool. Create only one of these, and it should be static. A ForkJoinPool is a pool of Threads. Java will take care of all the thread allocation and deallocation for you. 4
5
Incrementor IV package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Incrementor extends RecursiveTask<Integer> { public static ForkJoinPool fjPool = new ForkJoinPool(); int theNumber; Incrementor(int x) { theNumber = x; } public Integer compute() { return theNumber + 1; } public static void main(String[] args) { int fortyThree = fjPool.invoke(new Incrementor(42)); Systemout.println(fortyThree); } } Make an instance of our Incrementor class. We defined it to have a “generic” type parameter <Integer>, so let's define a field “theNumber” to hold it. In this example, our constructor sets theNumber to have an initial value. 5
6
Incrementor V Define a compute() method.
package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Incrementor extends RecursiveTask<Integer> { public static ForkJoinPool fjPool = new ForkJoinPool(); int theNumber; Incrementor(int x) { theNumber = x; } public Integer compute() { return theNumber + 1; } public static void main(String[] args) { int fortyThree = fjPool.invoke(new Incrementor(42)); System.out.println(fortyThree); } } Define a compute() method. compute() is what we use in place of run(). 6
7
Incrementor VI package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Incrementor extends RecursiveTask<Integer> { public static ForkJoinPool fjPool = new ForkJoinPool(); int theNumber; Incrementor(int x) { theNumber = x; } public Integer compute() { return theNumber + 1; } public static void main(String[] args) { int fortyThree = fjPool.invoke(new Incrementor(42)); System.out.println(fortyThree); } } Finally, create a new Incrementor (like getting a Thread, but with a parameter), and tell the ForkJoinPool to invoke it (like calling its “start” method). Calling “invoke” will cause “run” to be executed. 7
8
What did that code do? int fortyThree = fjPool.invoke(new Incrementor(42)); How is this any different from int fortyThree = new Incrementor(42).compute(); ? Answer: compute runs as a RecursiveTask (because class Incrementor extends RecursiveTask<Integer>) So what? RecursiveTasks are “lightweight” Threads (you can have up to of them) which can fork and join public final ForkJoinTask<V> fork() arranges to asynchronously execute this task. Any given task should only be forked once. public final V join(), unlike the Thread join, returns a result.
9
Summing an array I: Context
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class Globals { static ForkJoinPool fjPool = new ForkJoinPool(); } class Sum extends RecursiveTask<Long> { protected Long compute() {…} static long sumArray(int[] array) {…} We only ever need or want one ForkJoinPool: Let’s make a RecursiveTask/compute() combination: 9
10
Summing an array II: Parameters
class Sum extends RecursiveTask<Long> { static final int SEQUENTIAL_THRESHOLD = 5000; int low; int high; int[] array; Sum(int[] arr, int lo, int hi) { array = arr; low = lo; high = hi; } protected Long compute() {…} static long sumArray(int[] array) {…} We need to pass parameters in to compute(). But compute() doesn’t take parameters! What do we do? Notice the constructor ! 10
11
Summing an array III: Doing the work
class Sum extends RecursiveTask<Long> { protected Long compute() { if(high - low <= SEQUENTIAL_THRESHOLD) { long sum = 0; for(int i=low; i < high; ++i) sum += array[i]; return sum; } else { int mid = low + (high - low) / 2; Sum left = new Sum(array, low, mid); Sum right = new Sum(array, mid, high); left.fork(); long rightAns = right.compute(); long leftAns = left.join(); return leftAns + rightAns; } Not much to do? Do it here. Split the array into two parts. Start another thread to sum the left half. I’ll do the right half myself. When I’m done, wait for the other thread. 11
12
Let’s see that again We create two new Sums, one to fork and one to use ourself Sum left = new Sum(array, low, mid); Sum right = new Sum(array, mid, high); We fork to sum the left half of the array left.fork(); We sum the right half ourselves, with a plain old method call (not an additional Thread) that returns a result long rightAns = right.compute(); When we are done, the fork may or may not be done. We wait for it. When it is done, we get its result long leftAns = left.join(); Then, of course, we add the two results return leftAns + rightAns; 12
13
Summing an array IV: Begin here
class Sum extends RecursiveTask<Long> { // other methods that we have been looking at static long sumArray(int[] array) { return Globals.fjPool.invoke(newSum(array,0,array.length)); } } The call to fjPool.invoke creates an instance of this Sum class, which is a RecursiveTask, and that gets the ball rolling. invoke should not be called from within a RecursiveTask or RecursiveAction. It should only be called from sequential code. 15
14
Running the example import java.util.Random; public class SumTester {
static Random rand = new Random(); public static void main(String[] args) { int[] array = new int[100000]; for (int i = 0; i < array.length; i += 1) { array[i] = rand.nextInt(11); } long sum = Sum.sumArray(array); System.out.println(sum);
15
The End
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.