java并发Fork/join框架-java并发编程的艺术




 
  
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 {

	/** 
	 * @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 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
 * 			
 * 
 */

java并发Fork/join框架-java并发编程的艺术_第1张图片

你可能感兴趣的:(Java基础,并发)