1 apr 5, 2012 forkjoin new in java 7. incrementor i package helloworld; import...

15
1 Apr 5, 2012 ForkJoin New in Java 7

Upload: cameron-francis

Post on 12-Jan-2016

213 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

1Apr 5, 2012

ForkJoin

New in Java 7

Page 2: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Incrementor I package helloWorld;

import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;

2

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.

Page 3: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Incrementor II package helloWorld;

import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;

class Incrementor extends RecursiveTask<Integer> {

}

3

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.

Page 4: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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();

}

4

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.

Page 5: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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); }}

5

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.

Page 6: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Incrementor V 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); }}

6

Define a compute() method.compute() is what we use in place of run().

Page 7: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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); }}

7

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.

Page 8: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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 32767 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.

Page 9: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Summing an array I: Contextimport 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) {…}}

9

We only ever need or want one ForkJoinPool:

Let’s make a RecursiveTask/compute() combination:

Page 10: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Summing an array II: Parametersclass 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) {…}

} 10

We need to pass parameters in to compute().

But compute() doesn’t take parameters! What do we do?

Notice the constructor !

Page 11: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

Summing an array III: Doing the workclass 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; } }}

11

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.

Page 12: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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 anadditional 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

Page 13: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

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

Page 14: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

14

Running the exampleimport 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);

}

}

Page 15: 1 Apr 5, 2012 ForkJoin New in Java 7. Incrementor I package helloWorld; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;

15

The End