3

問題を示す簡単なテスト:

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class Main extends RecursiveTask<Long> {
    private volatile long start;
    private volatile long end;
    private volatile int deep;

    public Main(long start, long end, int index, int deep) {
        this.start = start;
        this.end = end;
        this.deep = deep;
//        System.out.println(deep + "-" + index);
    }

    @Override
    protected Long compute() {
        long part = (end - start) / 10;
        if (part > 1000 && deep < 10) {
            List<RecursiveTask<Long>> subtasks = new ArrayList<RecursiveTask<Long>>();
            for (int i = 0; i < 10; i++) {
                long subtaskEnd = start + part;
                if (i == 9) {
                    subtaskEnd = end;
                }
                subtasks.add(new Main(start, subtaskEnd, i, deep + 1));
                start = subtaskEnd;
            }

            //CASE 1: generates 3000+ threads
            for (int i = 0; i < 10; i++) {
                subtasks.get(i).fork();
            }

            //CASE 2: generates 4 threads
//            invokeAll(subtasks);

            //CASE 3: generates 4 threads
//            for (int i = 9; i >= 0; i--) {
//                subtasks.get(i).fork();
//            }


            long count = 0;
            for (int i = 0; i < 10; i++) {
                count += subtasks.get(i).join();
            }
            return count;
        } else {
            long startStart = start;
            while (start < end) {
                start += 1;
            }
            return start - startStart;
        }
    }

    private static ForkJoinPool executor = new ForkJoinPool();

    public static void main(String[] args) throws Exception {
        ForkJoinTask<Long> forkJoinTask = executor.submit(new Main(0, Integer.MAX_VALUE / 10, 0, 0));

        Long result = forkJoinTask.get();
        System.out.println("Final result: " + result);
        System.out.println("Number of threads: " + executor.getPoolSize());
    }

}

このサンプルでは、​​単純に数値を数えて CPU に負荷をかける RecursiveTask を作成します。着信範囲を再帰的に 10 の部分に分割し、部分のサイズが 1000 未満または再帰の「深さ」が 10 を超えると、数値のカウントを開始します。

compute() メソッドには 3 つのケースがコメントされています。違いは、サブタスクをフォークする順序のみです。サブタスクをフォークする順序によって、最終的なスレッドの数が異なります。私のシステムでは、最初のケースでは 3000 以上のスレッドが作成され、2 番目と 3 番目のケースでは 4 つのスレッドが作成されます。

質問: 違いは何ですか? このフレームワークをうまく使用するには、その内部構造を知る必要がありますか?

4

1 に答える 1

3

これは、私が 2011 年の記事「 A Java Fork-Join Calamity」で取り上げた古い問題です。記事は、修正を示すパート II を指していますか? Java8 でこれを実現します (余分なスレッドの代わりにストールを使用します)。

このフレームワークでは、専門的に多くのことを行うことはできません。他にも使用できるフレームワークがあります。

于 2013-09-10T17:46:47.383 に答える