ExecutorService and Problem
用一個 ExecutorService submit task 後, 如果 task 會 submit 其他的 task, 這些 task 都會放進 ExecutorService 的 queue 中.
這樣就沒辦法做到 "第一個 task 與其產生的 subtask 完成後就印一行 log"
ForkJoinPool and Purpose
使用了 ForkJoinPool 就可以透過 task 的 fork 與 join 讓 task 變成樹狀結構.
- 建立 ForkJoinPool
- 用 ForkJoinPool submit task
- task 建立幾個新的 subtask
- 呼叫 subtask 的 fork
- 呼叫 subtask 的 join
- 執行到 parent 的 task 結束
如此就能讓 task 自然分群
Reference and Sample
Code
public class ForkJoinPoolMain {
private static AtomicInteger actionCounter = new AtomicInteger();
public static void main(String[] params) throws ExecutionException, InterruptedException {
ForkJoinPool pool = new ForkJoinPool();
System.out.println("main:" + pool.submit(new MyAction(new int[]{1,2,3,4,5,6,7,8,9,10,11})).get());
}
private static class MyAction extends RecursiveTask<Integer> {
// Extends RecursiveAction if no return value required
private int count;
private int[] numbers;
public MyAction(int[] numbers) {
this.count = actionCounter.incrementAndGet();
this.numbers = numbers;
}
@Override
protected Integer compute() {
if (numbers.length > 2) {
System.out.println(count + " split " + Arrays.toString(numbers) + " to 2 arrays");
List<MyAction> actions = new ArrayList<>();
actions.add(new MyAction(Arrays.copyOfRange(numbers, 0, numbers.length / 2)));
actions.add(new MyAction(Arrays.copyOfRange(numbers, numbers.length / 2, numbers.length)));
actions.forEach(MyAction::fork);
return actions.stream().mapToInt(MyAction::join).sum();
} else if (numbers.length == 2) {
System.out.println(count + " add " + numbers[0] + " and " + numbers[1]);
return numbers[0] + numbers[1];
}
System.out.println(count + " just return " + numbers[0]);
return numbers[0];
}
}
}
下篇:ForkJoinPool 沒處理好也會 deadlock


沒有留言:
張貼留言