Fork/Join 框架

ForkJoinPool

1、JDK 1.7 加入的新的线程池实现,Fork / Join 框架的实现

2、体现分治思想,适用于能够进行任务拆分的 CPU 密集型运算

(1)任务拆分:将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解

(2)在分治的基础上加入多线程,把每个任务的分解、合并,交给不同的线程来完成

3、Fork / Join 默认创建与 CPU 核心数大小相同的线程池

4、系统对 ForkJoinPool 线程池进行优化

(1)提交的任务数量与线程的数量不一定是一对一关系

(2)在多数情况下,一个物理线程实际上需要处理多个逻辑任务

5、向线程池提交一个 ForkJoinTask 任务

ForkJoinTask submit(ForkJoinTask task)

(1)ForkJoinTask 任务支持 fork() 分解、join() 等待的任务

(2)不需要直接继承 ForkJoinTask 类,只需要继承它的子类:RecursiveAction、RecursiveTask

(3)RecursiveAction 任务没有返回值

(4)RecursiveTask 任务可以带有返回值,继承后可以实现递归调用的任务

6、组成

(1)ForkJoinTask 数组:存放任务、提交任务给 ForkJoinPool

(2)ForkJoinWorkerThread 数组:执行任务

 

fork 方法

1、程序会把任务放在 ForkJoinWorkerThread 的 pushTask 的 workQueue 中

2、异步地执行这个任务,然后立即返回结果

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;
}

3、push 方法

(1)把当前任务存放在 ForkJoinTask 数组队列里

(2)然后再调用 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();
    }
}

 

join 方法

1、阻塞当前线程,并等待获取结果

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

2、四种任务状态

(1)已完成(NORMAL)

(2)被取消(CANCELLED)

(3)信号(SIGNAL)

(4)出现异常(EXCEPTIONAL)

3、doJoin() 得到当前任务的状态,判断返回结果

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

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

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

4、doJoin() 流程

(1)首先通过查看任务的状态,看任务是否已经执行完成,如果执行完成,则直接返回任务状态

(2)如果没有执行完,则从任务数组里取出任务并执行

(3)如果任务顺利执行完成,则设置任务状态为 NORMAL,如果出现异常,则记录异常,并将任务状态设置为 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, 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;
}

 

Fork / Join 框架的异常处理

1、ForkJoinTask 在执行时,可能会抛出异常,但无法在主线程里直接捕获异常

2、isCompletedAbnormally():检查任务是否已经抛出异常,或已经被取消

3、getException

(1)返回 Throwable 对象

(2)如果任务被取消,则返回 CancellationException

(3)如果任务没有完成,或没有抛出异常,则返回 null

posted @   半条咸鱼  阅读(78)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示