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
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战