有些应用使用了大量线程,大其中大多数是空闲的。举例来说,一个Web服务器可能会为每个连接分别使用一个线程。另外一些应用可能对每个处理器内核分别使用一个线程,来完成计算密集型任务,如图像或者视频处理。Java SE7中新引入了fork-join框架,专门用来支持后一类应用。
在后台,fork-join框架使用一种有效的智能方法来平衡可用线程的工作负载,这种方法称为工作密取(work stealing)。每个工作线程都有一个双端队列(deque)来完成任务。一个工作线程将子任务压入其双端队列的队头。(只有一个线程可用访问队头,所以不需要加锁。)一个工作线程空闲时,它会从另一个双端队列的队尾“密取”一个任务。由于大的子任务都在队尾,这种密取很少出现。
Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为大任务结果。其思想和MapReduce的思想非常类似。对于任务的分割,要求各个子任务之间相互独立,能够并行独立地执行任务,互相之间不影响。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.IntStream;
public class ForkJoinRecurisiveTask {
//最大计算数
private static final int MAX_THRESHOLD = 5;
public static void main(String[] args) {
//创建ForkJoinPool
ForkJoinPool pool = new ForkJoinPool();
//异步提交RecursiveTask任务
ForkJoinTask<Integer> forkJoinTask = pool.submit(new CalculatedRecurisiveTask(0,10));
try {
//根据返回类型获取返回值
Integer result = forkJoinTask.get();
System.out.println("结果为:"+result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
private static class CalculatedRecurisiveTask extends RecursiveTask<Integer>{
private int start;
private int end;
public CalculatedRecurisiveTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
//判断计算范围,如果小于等于5,那么一个线程计算就够了,否则进行分割
if ((end-start)<=5) {
return IntStream.rangeClosed(start, end).sum();
}else {
//任务分割
int middle = (end+start)/2;
CalculatedRecurisiveTask task1 = new CalculatedRecurisiveTask(start,middle);
CalculatedRecurisiveTask task2 = new CalculatedRecurisiveTask(middle+1,end);
//执行
/* task1.fork(); task2.fork(); */
//invokeAll方法接收到很多任务并阻塞,直到所有任务都已经完成。join方法将生成结果。
invokeAll(task1, task2);
//等待返回结果
int leftResult = task1.join();
int rightResult = task2.join();
return leftResult + rightResult;
}
}
}
}
参考网址:
1、https://blog.csdn.net/youanyyou/article/details/78990280