JDK1.7提供的Fork/Join框架,用于把大任务拆解成小任务,多线程运行这些小任务,最后把小任务的结果求和。看到这个思想,是否觉得很熟悉?这个和算法里的分治算法如出一辙,Divide and Conquer,分而治之,各个击破。可以看做是分治算法的并行框架。从字面上理解,Fork,复制,把一个大任务切割并拷贝成多份小任务;Join,合并,把所有小任务的结果合并成大任务的结果。
这本书给出了一个示例,利用Fork/Join计算1+2+3+4,我觉得没意思。自己写了个demo,统计一个大文件夹下有多少个子文件。以前写过类似的程序,如果单线程下,那么可以利用DFS或者BFS算法求解。感觉这个Fork/Join就是一个多线程版本的DFS算法框架。给出我自己写的应用demo:
package chapter06;
import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
/**
* Created by cdlvsheng on 2016/4/4.
*/
public class CountFileTask extends RecursiveTask<Integer> {
private File file;
public CountFileTask(File f) {
this.file = f;
}
@Override
protected Integer compute() {
int sum = 0;
File[] list = file.listFiles();
for (File f : list) {
if (f.isDirectory()) {
CountFileTask cft = new CountFileTask(f);
cft.fork();
sum += cft.join();
} else sum++;
}
return sum;
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
CountFileTask task = new CountFileTask(new File("D:\\Code_Git"));
long start = System.currentTimeMillis();
Future<Integer> result = forkJoinPool.submit(task);
try {
System.out.println(result.get());
long duration = System.currentTimeMillis() - start;
System.out.println("time cost: " + duration + " ms");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
给出运行结果:
4340
time cost: 164 ms
再看下微软的统计截图
统计结果十分精准,而且耗时仅仅164ms。
简单的解释下背后的工作原理。ForkJoinPool会创建一个一个线程池,同时构建一个ForkJoinTask队列。RecursiveTask的fork方法会将自己push进ForkJoinPool实例的ForkJoinTask队列里。RecursiveTask的join方法则会阻塞当前线程,直到线程任务完成。