Я читал структуру Java ForkJoin. Какие дополнительные преимущества существуют, если нет прямого вызова invoke()
по реализации ForkJoinTask
(например, RecursiveTask
), но для создания экземпляра ForkJoinPool
и вызова pool.invoke(task)
? Что именно происходит, когда мы называем эти 2 метода все называемыми invoke
?ForkJoinPool.invoke() и ForkJoinTask.invoke() или compute()
От источника кажется, что если вызывается recursiveTask.invoke
, он будет вызывать его exec
и, в конечном итоге, compute
, в пуле управляемого потока. Как таковой, это еще более запутанно, почему у нас есть идиома pool.invoke(task)
.
Я написал несколько простых кодов для проверки разницы в производительности, но я их не видел. Может быть, тестовый код неправильный? Смотрите ниже:
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' также имеет унаследованный метод' invoke', и обычно вызывается 'invoke' внутри его основного метода' compute'. Что это значит? И все-таки, почему нет различий в производительности? – Boyang
Итак, я копаю исходный код. Если вызывается 'recursiveTask.invoke', он будет вызывать его' exec' и в конечном итоге 'compute' в пуле управляемых потоков. В таком случае меня еще больше путают с идиомой 'pool.invoke (task)'. Зачем? – Boyang
Обратитесь к моим новым изменениям – Boyang