1. 思想
2. 使用接口
RecursiveTask:用于任务有返回结果的场景。
RecursiveAction:用于任务没有返回结果的场景。
3. 简单用例
CountForkJoinTask :数字求和。
设计思路:
package com.john.learn.high.concurent.ch03.threadpool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
public class CountForkJoinTask extends RecursiveTask<Long> {
/**
*
*/
private static final long serialVersionUID = 1L;
private long start;
private long end;
public CountForkJoinTask(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (isThresholdComputed()) {
long sum = 0;
for (long i = this.start; i <= this.end; i++) {
sum += i;
}
return sum;
}
// 分成Party_Size_Division小任务
long step = (this.end - this.start) / Party_Size_Division;
List<CountForkJoinTask> countForkJoinTasks = new ArrayList<>(Party_Size_Division);
long pos = start;
for (int i = 0; i < Party_Size_Division; i++) {
long lastOne = Math.min(pos + step, this.end);
CountForkJoinTask countForkJoinTask = new CountForkJoinTask(pos, lastOne);
countForkJoinTask.fork();
countForkJoinTasks.add(countForkJoinTask);
if (lastOne == this.end) {
break;
}
pos = lastOne + 1;
}
long sum = 0;
for (CountForkJoinTask countForkJoinTask : countForkJoinTasks) {
sum += countForkJoinTask.join();
}
return sum;
}
private boolean isThresholdComputed() {
return (this.end - this.start) < Threshold_Computation;
}
private static final int Threshold_Computation = 1000;
private static final int Party_Size_Division = 100;
public static void main(String[] args) throws InterruptedException, ExecutionException {
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> forkJoinTask = forkJoinPool.submit(new CountForkJoinTask(1, 900000000l));
System.out.println(forkJoinTask.get());
}
}
FibonacciForkJoinTask: F(n)=F(n-1)+F(n-2)
package com.john.learn.high.concurent.ch03.threadpool;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class FibonacciForkJoinTask extends RecursiveTask<BigDecimal> {
private static final long serialVersionUID = 1L;
final int n;
FibonacciForkJoinTask(int n) {
this.n = n;
}
@Override
protected BigDecimal compute() {
if (Hot_Result_Map.containsKey(n)) {
return Hot_Result_Map.get(n);
}
if (n <= Fibonacci_Smaller_Array.length - 1) {
return compute(this.n);
}
FibonacciForkJoinTask f1 = new FibonacciForkJoinTask(n - 1);
FibonacciForkJoinTask f2 = new FibonacciForkJoinTask(n - 2);
f1.fork();
f2.fork();
BigDecimal a = f1.join();
BigDecimal b = f2.join();
Hot_Result_Map.put(n - 1, a);
Hot_Result_Map.put(n - 2, b);
Hot_Result_Map.put(n, a.add(b));
return a.add(b);
}
private BigDecimal compute(int small) {
return BigDecimal.valueOf(Fibonacci_Smaller_Array[this.n]);
}
private static Map<Integer, BigDecimal> Hot_Result_Map = new ConcurrentHashMap<>();
private static final long[] Fibonacci_Smaller_Array = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
public static void main(String[] args) throws InterruptedException, ExecutionException {
FibonacciForkJoinTask fibonacciForkJoinTask = new FibonacciForkJoinTask(100);
ForkJoinPool forkJoinPool = new ForkJoinPool();
System.out.println(forkJoinPool.submit(fibonacciForkJoinTask).get());
}
}
FileForkJoinTask:文件及文件夹下文件遍历
package com.john.learn.high.concurent.ch03.threadpool;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
public class FileForkJoinTask extends RecursiveTask<List<File>> {
/**
*
*/
private static final long serialVersionUID = 1L;
private File file;
public FileForkJoinTask(File file) {
this.file = file;
}
@Override
protected List<File> compute() {
if (file.isFile()) {
List<File> files = new ArrayList<>(1);
files.add(file);
return files;
}
List<FileForkJoinTask> fileForkJoinTasks = new ArrayList<>();
for (File _file : file.listFiles()) {
FileForkJoinTask fileForkJoinTask = new FileForkJoinTask(_file);
fileForkJoinTask.fork();
fileForkJoinTasks.add(fileForkJoinTask);
}
List<File> files = new ArrayList<>();
for (FileForkJoinTask fileForkJoinTask : fileForkJoinTasks) {
files.addAll(fileForkJoinTask.join());
}
return files;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<List<File>> forkJoinTask = forkJoinPool.submit(
new FileForkJoinTask(new File("E:\\eProjects\\")));
System.out.println(forkJoinTask.get());
}
}
4.实现要素
1. 递归思想
2. 任务窃取
由于线程池的优化,提交的任务和线程数量并不是一对一的关系。
在绝大多数情况下,个物理线程实际上是需要处理多个逻辑任务的。
因此,每个线程必然需要拥有一个任务队列因此,在实际执行过程中,可能遇到这么一种情况:
线程A已经把自己的任务都执行完成了,而线程B还有一堆任务等着处理,此时,线程A就会“帮助”线程B,从线程B的任务队列中拿一个任务过来处理,尽可能地达到平衡。
如图3.9所示,显示了这种互相帮助的精神。
一个值得注意的地方是,当线程试图帮助别人时,总是从任务队列的底部开始拿数据,而线程试图执行自己的任务时,则是从相反的顶部开始拿。
因此这种行为也十分有利于避免数据竞争。