I was reading Java ForkJoin framework. What extra benefits are there by not directly call invoke()
on an implementation of ForkJoinTask
(e.g. RecursiveTask
), but to instantiate ForkJoinPool
and call pool.invoke(task)
? What exactly happens when we call these 2 methods all called invoke
?
From the source, it seems that if recursiveTask.invoke
is called, it will invoke its exec
and eventually compute
, in a managed thread pool manner. As such it's even more confusing why we have the idiom pool.invoke(task)
.
I wrote some simple code to test for performance difference, but I didn't see any. Maybe the test code is wrong? See below:
public class MyForkJoinTask extends RecursiveAction {
private static int totalWorkInMillis = 20000;
protected static int sThreshold = 1000;
private int workInMillis;
public MyForkJoinTask(int work) {
this.workInMillis = work;
}
// Average pixels from source, write results into destination.
protected void computeDirectly() {
try {
ForkJoinTask<Object> objectForkJoinTask = new ForkJoinTask<>();
Thread.sleep(workInMillis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void compute() {
if (workInMillis < sThreshold) {
computeDirectly();
return;
}
int discountedWork = (int) (workInMillis * 0.9);
int split = discountedWork / 2;
invokeAll(new MyForkJoinTask(split),
new MyForkJoinTask(split));
}
public static void main(String[] args) throws Exception {
System.out.printf("Total work is %d in millis.%n", totalWorkInMillis);
System.out.printf("Threshold is %d in millis.%n", sThreshold);
int processors = Runtime.getRuntime().availableProcessors();
System.out.println(Integer.toString(processors) + " processor"
+ (processors != 1 ? "s are " : " is ")
+ "available");
MyForkJoinTask fb = new MyForkJoinTask(totalWorkInMillis);
ForkJoinPool pool = new ForkJoinPool();
long startTime = System.currentTimeMillis();
// These 2 seems no difference!
pool.invoke(fb);
// fb.compute();
long endTime = System.currentTimeMillis();
System.out.println("Took " + (endTime - startTime) +
" milliseconds.");
}
}
RecursiveTask
also has a inheritedinvoke
method, and it's common to callinvoke
inside it's maincompute
method. What does that do then? And still, how come there's no performance differences? – Clinic