Fork/Join 框架

来源:互联网 发布:掌上电力显示网络异常 编辑:程序博客网 时间:2024/04/28 10:04

ForkJoin 将大任务分割成小任务,若子任务还不够小则继续分割,最后执行任务合并结果。

  1. ForkJoinTask: 我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。他提供了在任务中执行fork()和join()操作机制。RecursiveTask有返回值的子类RecursiveAction 没有返回值的之类。
  2. ForkJoinPool :ForkJoinTask需要使用ForkJoinPool 来执行。

举例:下面计算1+2+3+…+9+10
每个子任务计算三个数相加

package com.john;import java.util.concurrent.ExecutionException;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.Future;import java.util.concurrent.RecursiveTask;public class ForkJoinTest {//其中RecursiveTask<Integer>时ForkJoin实现类,直接继承即可。//若子任务是没有返回值的则直接继承RecursiveAction 实现类。    public class CountTask extends RecursiveTask<Integer>{        private int s;        private int e;        private final static int  THRESHOLD=3;        public CountTask(int s,int e)        {            this.s=s;            this.e=e;        }        @Override        protected Integer compute() {            int ret=0;            //每个子任务计算三个数相加            if(e-s>THRESHOLD)            {                int mid=(s+e)/2;                CountTask left=new CountTask(s, mid);                CountTask right=new CountTask(mid+1, e);                left.fork();                right.fork();                //取得子任务的结果并合并结果                int l=left.join();                int r=right.join();                ret=l+r;            }            else{                for(int i=s;i<=e;i++)                {                    ret+=i;                }            }            System.out.println("当前线程名:"+Thread.currentThread().getName()+"  计算从"+s+"到"+e+"的结果为:"+ret);            return ret;        }    }    public static void main(String[] args) throws InterruptedException, ExecutionException {        ForkJoinPool pool=new ForkJoinPool();        ForkJoinTest test=new ForkJoinTest();        CountTask c=test.new CountTask(1, 10);        Future<Integer> future=pool.submit(c);        System.out.println(future.get().intValue());    }}
输出结果:当前线程名:ForkJoinPool-1-worker-1  计算从13的结果为:6当前线程名:ForkJoinPool-1-worker-0  计算从910的结果为:19当前线程名:ForkJoinPool-1-worker-2  计算从68的结果为:21当前线程名:ForkJoinPool-1-worker-2  计算从610的结果为:40当前线程名:ForkJoinPool-1-worker-3  计算从45的结果为:9当前线程名:ForkJoinPool-1-worker-1  计算从15的结果为:15当前线程名:ForkJoinPool-1-worker-1  计算从110的结果为:5555

Fork/Join如何处理异常?
task.isCompletedAbnormally()用于判断任务是否有异常,若有,可以使用task.getException()获得异常信息。

实现原理:
ForkJoinTask 的fork()原理:

  public final ForkJoinTask<V> fork() {        Thread t;        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)        //push()将ForkJoinTest 压入队列,然后调用ForkJoinPool的singalWork()来唤醒或创建一个工作线程            ((ForkJoinWorkerThread)t).workQueue.push(this);        else            ForkJoinPool.common.externalPush(this);        return this;    }

ForkJoinTask的join()方法原理

 public final V join() {        int s;        if ((s = doJoin() & DONE_MASK) != NORMAL)            reportException(s);        return getRawResult();    }    //首先查看任务状态,若任务执行完成,直接返回结果,若为执行完,则从任务数组中取出并执行,若跑出异常,则记录异常,并将任务状态设置为EXCEPTIONAL   private int doJoin() {        int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;        return (s = status) < 0 ? s :            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?            (w = (wt = (ForkJoinWorkerThread)t).workQueue).            tryUnpush(this) && (s = doExec()) < 0 ? s :            wt.pool.awaitJoin(w, this) :            externalAwaitDone();    }
0 0
原创粉丝点击