ForkJoin的基本介绍和应用

ForkJoinPool 框架主要类:

ForkJoinPool 实现ForkJoin的线程池 - ThreadPool

  • ForkJoinWorkerThread  实现ForkJoin的线程

ForkJoinTask 一个描述ForkJoin的抽象类 Runnable/Callable

  • RecursiveAction 无返回结果的ForkJoinTask实现Runnable
  • RecursiveTask 有返回结果的ForkJoinTask实现Callable
  • CountedCompleter 在任务完成执行后会触发执行一个自定义的钩子函数

ForkJoinPool 实现了Executor Service 接口

  • ExecutorService Java Executor框架的基础类
  • 其他ExecutorService的实现执行RunnableCallables任务
  •  ForkJoinPool执行ForkJoinTasks任务

ForkJoin的基本介绍和应用_第1张图片

可以通过Executors. newWorkStealPool创建ForkJoinPool

ForkJoin的基本介绍和应用_第2张图片


ForkJoinPool任务提交方式:

  1. public void execute(ForkJoinTask task)
    public void execute(Runnable task)
  2. public  T invoke(ForkJoinTask task)
  3. public  List> invokeAll(Collection> tasks)
  4. public  ForkJoinTask submit(ForkJoinTask task)
    public  ForkJoinTask submit(Callable task)
    public  ForkJoinTask submit(Runnable task, T result)
    public ForkJoinTask submit(Runnable task)

ForkJoinTask主要包括两个方法分别实现任务的分拆与合并:

ForkJoin的基本介绍和应用_第3张图片

ForkJoin的基本介绍和应用_第4张图片

fork()类似于Thread.start(),但是它并不立即执行任务,而是将任务放入工作队列中。

跟Thread.join()不同,ForkJoinTaskjoin()方法并不简单的阻塞线程,利用工作线程运行其他任务,当一个工作线程中调用join(),它将处理其他任务,直到注意到目标子任务已经完成。


ForkJoinTask3个子类:

RecursiveAction

无返回值的任务

RecursiveTask

有返回值的任务

CountedCompleter

完成任务后将触发其他任务


  • 还是之前的数组求和的例子
class LongSum extends RecursiveTask {

    static final int SEQUENTIAL_THRESHOLD = 1000;

    private int low;
    private int high;
    private int[] array;

    LongSum(int[] arr, int lo, int hi) {
        this.array = arr;
        this.low = lo;
        this.high = hi;
    }

    @Override
    protected Long compute() {
        //System.out.println(Thread.currentThread().getName());
        if (high - low <= SEQUENTIAL_THRESHOLD) {

            long sum = 0;
            for (int i = low; i < high; ++i) {
                sum += array[i];
            }

            return sum;

        } else {
            int mid = low + (high - low) / 2;
            LongSum left = new LongSum(array, low, mid);
            LongSum right = new LongSum(array, mid, high);
            left.fork();
            long rightAns = right.compute();
            long leftAns = left.join();
            return leftAns + rightAns;
        }
    }
}

 

public class LongSumMain {

	static long calcSum;

	public static void main(String[] args) throws Exception {
		int[] array = Utils.buildRandomIntArray(20000000);

 		calcSum = seqSum(array);
		System.out.println("seq sum=" + calcSum);

		LongSum ls = new LongSum(array, 0, array.length);
  		ForkJoinPool fjp  = new ForkJoinPool(4); // with number of threads to use

		ForkJoinTask result = fjp.submit(ls);
		System.out.println("forkjoin sum=" + result.get());

		fjp.shutdown();
		
	}


	static long seqSum(int[] array) {
		long sum = 0;
		for (int i = 0; i < array.length; ++i)
			sum += array[i];
		return sum;
	}
}
  • 里面很好的思想就是,一半的程序可以交由当前线程完成,不需要也另外开一个线程去处理。例子中每次分左半部分和右半部分,左半部分可以开线程去处理,而右半部分就可以当前线程来处理。
  • RecursiveAction的简单应用

 

你可能感兴趣的:(架构师之路)