只要我在池中提供ForkJoinPool 一个额外的线程,它的执行速度与ExecutorService相同。以下是使用的三个类:Main,RunnableTask和ForkJoinTask。在16核盒上运行,程序每次输出: 执行人时间:5002 ForkJoin时间: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();
}
}
Runnable类:
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;
}
}
答案 0 :(得分:3)
您的个人任务可以使 ForkJoinPool
和ExecutorService
比现在更快地运行,而且任何人都不应该有实质性的优势在另一方面。
原因是如果单个计算任务是Thread.sleep(1000)
,则该任务不需要CPU资源。您可以增加线程数以匹配您的工作大小(80)并在超过1秒的时间内完成80秒的“工作”,因为线程不会真正竞争任何类型的资源。
至于ForkJoinPool
和ExecutorService
之间的比较,差异与您的测试用例无关,因为您的工作量不会导致任何应该作为进一步计算的输入(MapReduce中的'reduce'步骤)。所以对你来说,它们都只是具有不同API的线程池。