Fork/Join框架

概念  

Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork/Join框架要完成两件事情:

  1.任务分割:首先Fork/Join框架需要把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割

  2.执行任务并合并结果:分割的子任务分别放到双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,启动一个线程从队列里取数据,然后合并这些数据。

  在Java的Fork/Join框架中,使用两个类完成上述操作

  1.ForkJoinTask:我们要使用Fork/Join框架,首先需要创建一个ForkJoin任务。该类提供了在任务中执行fork和join的机制。通常情况下我们不需要直接集成ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了两个子类:

    a.RecursiveAction:用于没有返回结果的任务

    b.RecursiveTask:用于有返回结果的任务

  2.ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行

  任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务(工作窃取算法)。

Fork/Join框架的实现原理

  ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责将存放程序提交给ForkJoinPool,而ForkJoinWorkerThread负责执行这些任务。

  ForkJoinTask的Fork方法的实现原理:
  当我们调用ForkJoinTask的fork方法时,程序会把任务放在ForkJoinWorkerThread的pushTask的workQueue中,异步地执行这个任务,然后立即返回结果,代码如下:

public final ForkJoinTask<V> fork() {
        Thread t;
        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
            ((ForkJoinWorkerThread)t).workQueue.push(this);
        else
            ForkJoinPool.common.externalPush(this);
        return this;
    }

  pushTask方法把当前任务存放在ForkJoinTask数组队列里。然后再调用ForkJoinPool的signalWork()方法唤醒或创建一个工作线程来执行任务。代码如下:

final void push(ForkJoinTask<?> task) {
            ForkJoinTask<?>[] a; ForkJoinPool p;
            int b = base, s = top, n;
            if ((a = array) != null) {    // ignore if queue removed
                int m = a.length - 1;     // fenced write for task visibility
                U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
                U.putOrderedInt(this, QTOP, s + 1);
                if ((n = s - b) <= 1) {
                    if ((p = pool) != null)
                        p.signalWork(p.workQueues, this);
                }
                else if (n >= m)
                    growArray();
            }
        }

ForkJoinTask的join方法实现原理

  Join方法的主要作用是阻塞当前线程并等待获取结果。让我们一起看看ForkJoinTask的join方法的实现,代码如下:

public final V join() {
        int s;
        if ((s = doJoin() & DONE_MASK) != NORMAL)
            reportException(s);
        return getRawResult();
    }

  它首先调用doJoin方法,通过doJoin()方法得到当前任务的状态来判断返回什么结果,任务状态有4种:已完成(NORMAL)、被取消(CANCELLED)、信号(SIGNAL)和出现异常(EXCEPTIONAL)。

  如果任务状态是已完成,则直接返回任务结果。

  如果任务状态是被取消,则直接抛出CancellationException

  如果任务状态是抛出异常,则直接抛出对应的异常

  让我们分析一下doJoin方法的实现

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, 0L) :
            externalAwaitDone();
    }

final int doExec() {
        int s; boolean completed;
        if ((s = status) >= 0) {
            try {
                completed = exec();
            } catch (Throwable rex) {
                return setExceptionalCompletion(rex);
            }
            if (completed)
                s = setCompletion(NORMAL);
        }
        return s;
    }

  在doJoin()方法里,首先通过查看任务的状态,看任务是否已经执行完成,如果执行完成,则直接返回任务状态;如果没有执行完,则从任务数组里取出任务并执行。如果任务顺利执行完成,则设置任务状态为NORMAL,如果出现异常,则记录异常,并将任务状态设置为EXCEPTIONAL。

Fork/Join框架的异常处理

  ForkJoinTask在执行的时候可能会抛出异常,但是我们没办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常。使用如下代码:

if(task.isCompletedAbnormally())
{
    System.out.println(task.getException());
}

  getException方法返回Throwable对象,如果任务被取消了则返回CancellationException。如果任务没有完成或者没有抛出异常则返回null。

public final Throwable getException() {
        int s = status & DONE_MASK;
        return ((s >= NORMAL)    ? null :
                (s == CANCELLED) ? new CancellationException() :
                getThrowableException());
    }

以上转载自:https://www.cnblogs.com/senlinyang/p/7885964.html

使用案例

层层遍历文件夹,找到txt文件

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

/**
 * @Author: BillYu
 * @Description:遍历指定目录(含子目录)找到指定类型文件
 * Fork/Join的异步用法同时演示不要求返回值:遍历指定目录(含子目录) 寻找指定类型文件
 * @Date: Created in 18:22 2019-02-25.
 */
public class FindDirsFiles extends RecursiveAction {
    /**
     * 当前任务需要搜寻的目录
     */
    private File path;

    public FindDirsFiles(File path){
        this.path = path;
    }

    public static void main(String[] args) {
        try {
            //用一个ForkJoinPool 实例调度总任务
            ForkJoinPool pool = new ForkJoinPool();
            FindDirsFiles task = new FindDirsFiles(new File("/Users/yuwb/Documents/test"));
            //异步调用
            pool.execute(task);
            System.out.println("Task is Running....");
            Thread.sleep(1);
            int otherWork = 0;
            for (int i = 0;i<100;i++){
                otherWork = otherWork+i;
            }
            System.out.println("Main Thread done sth...,otherWork="+otherWork);
            //阻塞的方法
            task.join();
            System.out.println("Task end");
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    @Override
    protected void compute() {
        List<FindDirsFiles> subTasks = new ArrayList<>();
        File[] files = path.listFiles();
        if(files!=null){
            for (File file:files){
                if(file.isDirectory()){
                    subTasks.add(new FindDirsFiles(file));
                }else{
                    //遇到文件,检查
                    if(file.getAbsolutePath().endsWith("txt")){
                        System.out.println("文件:"+file.getAbsolutePath());
                    }
                }
            }
            if(!subTasks.isEmpty()){
                for (FindDirsFiles subTask:invokeAll(subTasks)){
                    //等待子任务完成
                    subTask.join();
                }
            }
        }

    }
}

2DE7A1C1-8A3C-4A9F-8377-E36E93BBFD40.png

已有 15 条评论
  1. cialis buy online

    Greetings from Idaho! I'm bored at work so I decided
    to browse your website on my iphone during lunch break. I love the info you
    present here and can't wait to take a look when I get home.
    I'm surprised at how quick your blog loaded on my mobile ..
    I'm not even using WIFI, just 3G .. Anyhow, superb blog!

    cialis buy online November 18th, 2019 at 01:15 pm回复
  2. KelSuefab

    Keflex Prescribing Info Venta Kamagra El Mundo Cialis Flussig Kaufen Buy Cialis Viagra Ohne Rezept Im Ausland Toradol Over Night

    KelSuefab January 16th, 2020 at 04:57 pm回复
  3. MatInfoge

    Viagra Effetti Secondari http://buyciaonlinex.com - Buy Cialis Viagra Naturale In Farmacia Cialis Augmentin Vs Amoxicillin

    MatInfoge January 27th, 2020 at 07:40 am回复
  4. StevWews

    Medrol Dose Pack 4 Mg No Rx http://cialisir.com - Buy Cialis Comparaison Cialis Levitra Buy Cialis Mail Order Clarithromycin 500 Mg

    StevWews January 28th, 2020 at 03:37 pm回复
  5. LesAstona

    Want To Buy Isotretinoin http://viacialisns.com - cialis 5mg Bactrim Prescription Urethritis Cialis Cialis Nelle Urine

    LesAstona January 29th, 2020 at 11:23 pm回复
  6. LesAstona

    Didanosine http://buyciallisonline.com/# - Cialis Viagra Generico Contrassegno Buy Cialis Viagra 100

    LesAstona February 9th, 2020 at 12:34 pm回复
  7. http://denemeofis.polatlikentotel.com/

    2016 Yılı En Iyi Kitapları Yeni Çıkan Kitaplar

    http://denemeofis.polatlikentotel.com/ February 20th, 2020 at 01:49 pm回复
  8. StevWews

    Propecia Estrogenos http://abuycialisb.com - cialis 5 mg best price usa Viagra E Effetti Collaterali generic cialis from india Cialis Pour Premiere Fois

    StevWews February 27th, 2020 at 03:22 am回复
  9. Stepsok

    Kamagra Anwendung Cialis Propecia Ayuda cialis Buy Amoxicillin 875 Mg

    Stepsok March 11th, 2020 at 08:27 pm回复
  10. Stepsok

    Propecia Dosage Women Buy Cialis Cialis Todos Los Dias Buy Cialis Propecia Hair Thickening

    Stepsok March 12th, 2020 at 04:36 am回复
  11. Janmit

    Buy Synthroid Online With No Prescription cialis Viagra Pillen Erfahrungen where to buy cialis online safely Macrobid Tablets Medication Cash Delivery Online

    Janmit March 19th, 2020 at 07:11 pm回复
  12. Janmit

    Doxycycline For Chlamydia Order Online Cialis Cialis Se Vende Con Receta Cialis Buy Nitrostat Without A Prescription

    Janmit March 19th, 2020 at 11:59 pm回复
  13. Stepsok

    Finasteride Propecia Side Effects п»їcialis Keflex Liquid 250mg Cialis For Sale Progesterone

    Stepsok March 20th, 2020 at 07:51 pm回复
  14. posture corrector brace

    Asking questions are actually nice thing if you are not understanding something totally, but this article presents pleasant understanding even.

    posture corrector brace March 20th, 2020 at 09:34 pm回复
  15. Stepsok

    Cialis Mit Online Rezept when will cialis go generic Fedex Shipping Hydrochlorothiazide Best Website Tablet Shop Visa Durham cialis without a doctor's prescription Where To Purchase Online Amoxicilina From Canada Free Shipping

    Stepsok March 21st, 2020 at 05:28 am回复
发表新评论