2

ForkJoinPoolにプール内の追加のスレッドを 1 つ与える限り、ExecutorService と同じくらい高速に実行されます。使用される 3 つのクラスは次のとおりです: Main、RunnableTask、および ForkJoinTask。16コアボックスで実行すると、プログラムは毎回次​​のように出力します: Executor Time: 5002 ForkJoin Time: 5002

メインクラス:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        runExecutor(80);
        runForkJoin(80);
    }

    public static void runForkJoin(int size) {
        ForkJoinPool fjp = new ForkJoinPool(17);
        long start = System.currentTimeMillis();
        fjp.invoke(new ForkJoinTask(size));
        System.out.println("ForkJoin Time: "
                + (System.currentTimeMillis() - start));
        fjp.shutdown();
    }

    public static void runExecutor(int size) throws InterruptedException {
        ExecutorService exec = Executors.newFixedThreadPool(16);
        CountDownLatch latch = new CountDownLatch(size);
        long start = System.currentTimeMillis();
        for (int i = 0; i < latch.getCount(); i++) {
            exec.submit(new RunnableTask(latch));
        }
        latch.await();
        System.out.println("Executor Time: "
                + (System.currentTimeMillis() - start));
        exec.shutdown();
    }
}

実行可能なクラス:

import java.util.concurrent.CountDownLatch;

public class RunnableTask implements Runnable {
    private CountDownLatch latch;

    public RunnableTask(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            latch.countDown();
        } catch (Exception e) {
        }
    }
}

RecursiveTask クラス:

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

public class ForkJoinTask extends RecursiveTask {
    private List<RecursiveTask> tasks;
    private int size;

    public ForkJoinTask(int size) {
        super();
        this.tasks = new ArrayList<>();
        this.size = size;
    }

    @Override
    protected Object compute() {
        for (int i = 0; i < size; i++) {
            RecursiveTask task = new RecursiveTask() {
                @Override
                protected Object compute() {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {

                    }
                    return null;
                }
            };
            task.fork();
            tasks.add(task);
        }

        for (RecursiveTask task : tasks) {
            task.join();
        }
        return null;
    }
}
4

1 に答える 1

3

個々のタスクは、と の両方 を現在よりも高速に実行できるようなものであり、さらに、どちらも他方よりも実質的な利点を持たないものです。ForkJoinPoolExecutorService

その理由は、個々のコンピューティング タスクが である場合、Thread.sleep(1000)そのタスクは CPU リソースを必要としないためです。ジョブのサイズ (80) に合わせてスレッドの数を増やし、80 秒の「作業」を 1 秒より少し長い時間で完了することができます。これは、スレッドが実際にはどのような種類のリソースでも競合しないためです。

ForkJoinPoolとの比較に関しては、少しの作業では、さらなる計算 ( MapReduceExecutorServiceの「削減」ステップ) への入力となるものは何も得られないため、違いはテスト ケースには関係ありません。つまり、どちらも API が異なるスレッド プールにすぎません。

于 2013-03-27T19:32:07.937 に答える