目录页:https://blog.csdn.net/u011294519/article/details/88367808
1.Fork/Join
1.1.有返回值示例
Fork/Join是将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
下面我参照大神:说好不能打脸的写法使用归并算法对一个无序数组排序来做一个比对。
大神原文:https://blog.csdn.net/yinwenjie/article/details/71915811
上代码:
创建数组:
package com.concurrent.coline.part4.forkjoin.util;
import java.util.Random;
/**
* 产生整形数组
*/
public class MakeArray {
//数组长度
public static final int ARRAY_LENGTH = 10000000;
public static int[] makeArray() {
//new一个随机数发生器
Random r = new Random();
int[] result = new int[ARRAY_LENGTH];
for (int i = 0; i < ARRAY_LENGTH; i++) {
//用随机数填充数组
result[i] = r.nextInt(ARRAY_LENGTH * 3);
}
return result;
}
}
归并数组并排序:
package com.concurrent.coline.part4.forkjoin.util;
public class MergeTool {
/**
* 合并两个有序数组
*
* @param array1
* @param array2
* @return
*/
public static int[] joinInts(int array1[], int array2[]) {
int destInts[] = new int[array1.length + array2.length];
int array1Len = array1.length;
int array2Len = array2.length;
int destLen = destInts.length;
// 只需要以新的集合destInts的长度为标准,遍历一次即可
for (int index = 0, array1Index = 0, array2Index = 0; index < destLen; index++) {
int value1 = array1Index >= array1Len ? Integer.MAX_VALUE : array1[array1Index];
int value2 = array2Index >= array2Len ? Integer.MAX_VALUE : array2[array2Index];
// 如果条件成立,说明应该取数组array1中的值
if (value1 < value2) {
array1Index++;
destInts[index] = value1;
}
// 否则取数组array2中的值
else {
array2Index++;
destInts[index] = value2;
}
}
return destInts;
}
}
普通方式的归并算法:
package com.concurrent.coline.part4.forkjoin.sort;
import com.concurrent.coline.part4.forkjoin.util.MakeArray;
import com.concurrent.coline.part4.forkjoin.util.MergeTool;
import java.util.Arrays;
/**
* 来源:http://blog.csdn.net/yinwenjie
*/
public class NormalMergeSort {
public static void main(String[] args) {
int inits[] = MakeArray.makeArray();
long beginTime = System.currentTimeMillis();
int results[] = forkits(inits);
long endTime = System.currentTimeMillis();
// 如果参与排序的数据非常庞大,记得把这种打印方式去掉
System.out.println("耗时=" + (endTime - beginTime));
}
// 拆分成较小的元素或者进行足够小的元素集合的排序
private static int[] forkits(int source[]) {
int sourceLen = source.length;
if (sourceLen > 2) {
int midIndex = sourceLen / 2;
int result1[] = forkits(Arrays.copyOf(source, midIndex));
int result2[] = forkits(Arrays.copyOfRange(source, midIndex, sourceLen));
// 将两个有序的数组,合并成一个有序的数组
int mer[] = MergeTool.joinInts(result1, result2);
return mer;
}
// 否则说明集合中只有一个或者两个元素,可以进行这两个元素的比较排序了
else {
// 如果条件成立,说明数组中只有一个元素,或者是数组中的元素都已经排列好位置了
if (sourceLen == 1
|| source[0] <= source[1]) {
return source;
} else {
int targetp[] = new int[sourceLen];
targetp[0] = source[1];
targetp[1] = source[0];
return targetp;
}
}
}
}
Fork/Join算法做归并排序
package com.concurrent.coline.part4.forkjoin.sort;
import com.concurrent.coline.part4.forkjoin.util.MakeArray;
import com.concurrent.coline.part4.forkjoin.util.MergeTool;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ForkJoinMergeSort {
public static void main(String[] args) throws Exception {
// 正式开始
ForkJoinPool pool = new ForkJoinPool();
int[] inits = MakeArray.makeArray();
MyTask task = new MyTask(inits);
long beginTime = System.currentTimeMillis();
pool.invoke(task);
long endTime = System.currentTimeMillis();
System.out.println("耗时=" + (endTime - beginTime));
}
/**
* 单个排序的子任务
*
* @author yinwenjie
*/
static class MyTask extends RecursiveTask<int[]> {
private int source[];
public MyTask(int source[]) {
this.source = source;
}
/* (non-Javadoc)
* @see java.util.concurrent.RecursiveTask#compute()
*/
@Override
protected int[] compute() {
int sourceLen = source.length;
// 如果条件成立,说明任务中要进行排序的集合还不够小
if (sourceLen > 2) {
int midIndex = sourceLen / 2;
// 拆分成两个子任务
MyTask task1 = new MyTask(Arrays.copyOf(source, midIndex));
MyTask task2 = new MyTask(Arrays.copyOfRange(source, midIndex, sourceLen));
invokeAll(task1, task2);
// 将两个有序的数组,合并成一个有序的数组
int result1[] = task1.join();
int result2[] = task2.join();
int mer[] = MergeTool.joinInts(result1, result2);
return mer;
}
// 否则说明集合中只有一个或者两个元素,可以进行这两个元素的比较排序了
else {
// 如果条件成立,说明数组中只有一个元素,或者是数组中的元素都已经排列好位置了
if (sourceLen == 1
|| source[0] <= source[1]) {
return source;
} else {
int targetp[] = new int[sourceLen];
targetp[0] = source[1];
targetp[1] = source[0];
return targetp;
}
}
}
}
}
结果比对:
普通方式:
Fork/Join算法:
可以看出Fork/Join节省了大量的的计算时间,更充分利用系统资源。
Fork/Join的知识点不仅仅这些,但是更多的是提供一种解决问题的思路,Fork/Join的写法可参照:https://www.liaoxuefeng.com/article/001493522711597674607c7f4f346628a76145477e2ff82000
1.2. 无返回值示例
package com.concurrent.coline.part4.forkjoin.noreturn;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/**
* 类说明:遍历指定目录(含子目录)找寻指定类型文件
*/
public class FindDirsFiles extends RecursiveAction {
private File path;//当前任务需要搜寻的目录
public FindDirsFiles(File path) {
this.path = path;
}
public static void main(String[] args) {
try {
// 用一个 ForkJoinPool 实例调度总任务
ForkJoinPool pool = new ForkJoinPool();
FindDirsFiles task = new FindDirsFiles(new File("F:/"));
pool.execute(task);//异步调用
System.out.println("Task is Running......");
Thread.sleep(1);
int otherWork = 0;
for (int i = 0; i < 100; i++) {
otherWork = otherWork + i;
}
System.out.println("Main Thread done sth......,otherWork=" + otherWork);
task.join();//阻塞的方法
System.out.println("Task end");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void compute() {
List<FindDirsFiles> subTasks = new ArrayList<>();
File[] files = path.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
subTasks.add(new FindDirsFiles(file));
} else {
//遇到文件,检查
if (file.getAbsolutePath().endsWith("txt")) {
System.out.println("文件:" + file.getAbsolutePath());
}
}
}
if (!subTasks.isEmpty()) {
for (FindDirsFiles subTask : invokeAll(subTasks)) {
subTask.join();//等待子任务执行完成
}
}
}
}
}
代码在concurrent-toolbar模块part4