package testforkandjoin;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
//RecursiveTask extends ForkJoinTask 用于有返回结果的任务
//RecursiveAction extends ForkJoinTask 用于没有返回结果的任务
//ForkJoinTask需要通过ForkJoinPool来执行
/**
*
* 工作窃取算法
* 干完活的线程,帮助其他线程干活,造成竞争,所以使用双端队列,被窃取任务线程从双端队列的头部拿任务执行,而窃取任务的线程从双端队列的尾部拿任务执行
* 优点:充分利用线程进行并行计算,减少了线程间的竞争
* 缺点:当双端队列里只有一个任务时,存在竞争。该算法会消耗过多的系统资源,创建了多个线程和双端队列
* @ClassName: CountTask
* @Description: TODO(当一个工作线程的队列中暂时没有任务时,它会随即从其他线程的队列尾部获取一个任务)
* @author 梦境迷离
* @date 2017-8-7 下午5:00:38
*
*/
public class CountTask extends RecursiveTask<Integer> {
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;
/**
* @Title: main
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @param args 设定文件
* @return void 返回类型
* @throws
*/
private static final int THRESGOLD = 2;//阈值
private int start;
private int end;
public CountTask(int start, int end){
this.start = start;
this.end = end;
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
//生成计算任务,负责计算1+2+3+4
CountTask task = new CountTask(1, 4);
//执行一个任务
Future<Integer> result = forkJoinPool.submit(task);
if(task.isCompletedAbnormally()){
System.out.println(task.getException());//检查是否跑出异常,或已经取消任务,取消:CancellationException,未完成/没有异常:null
}
try {
System.out.println(result.get());
} catch (Exception e) {
// TODO: handle exception
}
}
@Override
protected Integer compute() {
int sum = 0;
//如果任务足够小就计算任务
boolean canCompute = (end-start)<=THRESGOLD;
if(canCompute){
for(int i=start; i<=end; i++){
sum+=i;
}
}else {
//如果任务大于阈值,就分裂成两个小任务计算
int middle = (start+end)/2;
CountTask lefTask = new CountTask(start, middle);
CountTask rightTask = new CountTask(middle+1, end);
//执行子任务
//子任务1负责执行1+2,子任务2负责执行3+4
lefTask.fork();
rightTask.fork();
//等待子任务执行完,并得到结果
int leftResult = lefTask.join();
int rightResult = rightTask.join();
//合并任务
sum = leftResult+rightResult;
}
return sum;
}
}
/**
* ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成
* ForkJoinTask数组负责将存放程序交给ForkJoinPool的任务,而ForkJoinWorkerThread数组负责执行这些任务
*
* ForkJoinTask的fork方法内部调用了ForkJoinWorkerThread的pushTask方法,pushTaks方法把当前任务存放在ForkJoinTask数组队列中,
* 然后调用ForkJoinPool的signalWork()方法唤醒或创建一个工作线程来执行任务
*
* ForkJoinTaskd join方法内部调用了doJoin方法,通过该方法得到任务的状态,
* 1、已完成--返回结果
* 2、被取消--跑出Cancellation异常
* 3、信号--
* 4、异常--直接抛出对应的异常
* doJoin方法中,
* 1、查看任务状态
* -是否执行完成
* 是-返回任务状态
* 否-从任务数组中取出任务并执行
* -顺利完成--状态设置为normal
* -出现异常--记录异常,状态设置为exceptional
*
*
*/