Fork-Join框架的用途:
将一个庞大的任务,拆分成多个互不相关的子任务,分别执行,并汇总结果,得到最终结果。
什么是分而治之?
规模为N的问题,N<阈值,直接解决,N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到原问题的解。
有3个父类:
- RecursiveTask (有返回值的任务父类)
- RecursiveAction (无返回值任务的父类)
- ForkJoinTask(1,2的父类)
示例:
- 同步等待结果返回
ForkJoinPool.invoke
求解一个Int数组的和:
public class MyArray {
public static int arrSize = 1000;
public static Integer[] initArr() {
Integer[] arr = new Integer[arrSize];
Random random = new Random();
for (int i = 0; i < arrSize; i++) {
arr[i] = random.nextInt(arrSize * 4);
}
return arr;
}
}
普通方法求和
public class SumNormal {
public static void main(String[] args) throws InterruptedException {
Integer[] arr = MyArray.initArr();
long startTime = System.currentTimeMillis();
int result = 0;
for (int i = 0; i < arr.length; i++) {
result += arr[i];
Thread.sleep(1);
}
System.out.println("The count is "+result
+" spend time:"+(System.currentTimeMillis()-startTime)+"ms");
}
}
运行结果:
The count is 2008834 spend time:1039ms
Fork Join拆分方法求和
public class SumForkJoin {
//继承RecursiveTask实现Fork Join框架
private static class ForkJoinImpl extends RecursiveTask<Integer> {
private final static int THRESHOLD = MyArray.arrSize / 10;
Integer[] src;
int fromIndex;
int toIndex;
public ForkJoinImpl(Integer[] src, int fromIndex, int toIndex) {
this.src = src;
this.fromIndex = fromIndex;
this.toIndex = toIndex;
}
//必须重写的方法
@Override
protected Integer compute() {
if (toIndex - fromIndex < THRESHOLD) {
int count = 0;
for (int i = fromIndex; i <= toIndex; i++) {
count += src[i];
}
return count;
} else {
int mid = (fromIndex + toIndex) / 2;
ForkJoinImpl left = new ForkJoinImpl(this.src, this.fromIndex, mid);
ForkJoinImpl right = new ForkJoinImpl(this.src, mid, this.toIndex);
//递归调用所有RecursiveTask子类的compute
invokeAll(left, right);
//join获取RecursiveTask子类的结果
return left.join() + right.join();
}
}
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
Integer[] arr = MyArray.initArr();
long startTime = System.currentTimeMillis();
ForkJoinImpl impl = new ForkJoinImpl(arr, 0, arr.length - 1);
pool.invoke(impl);//同步方法
System.out.println("Task is Running.....");
System.out.println("The count is "+impl.join()
+" spend time:"+(System.currentTimeMillis()-startTime)+"ms");
}
}
运行结果:
Task is Running.....
The count is 2010582 spend time:9ms
根据结果对比,当任务需要花费时间时,可以发现串行任务比Fork-Join所花费的时间长.但是也不一定ForkJoin的时间就比串行时间段,因为ForkJoin底层实现为递归,所以存在上下文调度。
2. 异步返回没有结果
ForkJoinPool.execute
查询文件夹下的所有txt文件
public class FileSeacherForkJoin {
private static String file_suffix = "txt";
private static class FileSearchForkJoinImpl extends RecursiveAction {
File file;
public FileSearchForkJoinImpl(File file) {
this.file = file;
}
@Override
protected void compute() {
if (file.isDirectory()) {
List<FileSearchForkJoinImpl> list = new ArrayList<>();
File[] files = file.listFiles();
for (File file : files) {
if(file.isDirectory()){
list.add(new FileSearchForkJoinImpl(file));
}else{
if (file.getAbsolutePath().endsWith(file_suffix)) {
System.out.println("文件:" + file.getAbsolutePath());
}
}
}
if (!list.isEmpty()){
for (FileSearchForkJoinImpl impl : invokeAll(list)){
impl.join();
}
}
} else {
if (file.getAbsolutePath().endsWith(file_suffix)) {
System.out.println("文件:" + file.getAbsolutePath());
}
}
}
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
File file = new File("E:\\tomcat\\apache-tomcat-7.0.59");
FileSearchForkJoinImpl impl = new FileSearchForkJoinImpl(file);
pool.execute(impl);//异步执行没有返回值
System.out.println("main task is end");
impl.join();//阻塞
System.out.println("all task is done");
}
}
运行结果:
main task is end
文件:E:\tomcat\apache-tomcat-7.0.59\RUNNING.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-04-29.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-07-22.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-22.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-23.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-24.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-25.txt
all task is done