バックグラウンド
日常的なコンピューティング タスクのほとんどは逐次的に実行されますが、複雑なタスクを複数の小さなタスクに分割する必要がある場合、これまでは、再帰的または循環的なコンピューティング アルゴリズムを独自に記述することで実現していました。 Java7 では、このタイプの計算をサポートするようになりました。これにより、大規模なタスクや、組み合わせた計算が必要な一部のシナリオを効率的に解決できます。
ForkJoin フレームワークの概要
Java の Fork-Join フレームワークは、マルチスレッド並列処理タスク用のフレームワークであり、通常は CPU を集中的に使用するタスクを処理するために使用されます。これは Java SE 7 以降で提供されるクラス ライブラリであり、開発者がスケーラブルな並列コードをより簡単に作成できるように設計されています。
Fork-Join フレームワークの核となるアイデアは「分割統治アルゴリズム」です。これは、大きなタスクをいくつかの小さなサブタスクに分割し、これらのサブタスクを再帰的に処理し、最後にそれらの結果を結合して、タスクの大きな結果を取得します。 。各サブタスクを独立して実行できるため、マルチプロセッサやマルチコアCPUの利点を生かしてサブタスクを並列処理することができ、タスク全体の処理速度が向上します。
Fork-Join フレームワークを使用する場合は、RecursiveTask または RecursiveAction から継承したタスクを定義し、ForkJoinPool.submit() メソッドを使用してタスクを Fork-Join スレッド プールに送信して実行する必要があります。このうち、RecursiveTask はタスクの結果を返しますが、RecursiveAction は結果を返しません。
Fork-Join フレームワークは便利で使いやすいだけでなく、マルチプロセッサとマルチコア CPU を自動的に利用してハードウェア リソースの利点を最大限に活用できます。同時に、ワークスチールアルゴリズムなど、他の多くの詳細とパフォーマンス最適化対策も備えており、並列タスクを処理するための強力なツールとなっています。
推奨されるリファレンス: https://www.oracle.com/technical-resources/articles/java/fork-join.html
CPU 集中型と IO 集中型の違いは何ですか?
CPU 集中型と IO 集中型は、さまざまなタイプのコンピューティング タスクを指します。違いは主にシステム リソースの使用率にあります。
CPU 負荷の高いタスク (CPU バウンド) とは、複雑な数学的計算、画像処理、科学シミュレーションなど、完了するために大量の CPU 操作を必要とするタスクを指します。この場合、システムのハードディスクとメモリのパフォーマンスは CPU のパフォーマンスよりもはるかに優れており、このとき、CPU Loading は 100% になることが多く、I/O 操作は短時間で完了できます。そのため、I/O 負荷は 100% ですが、CPU 使用率は非常に高くなりますが、待ち時間が短いため、CPU は I/O 操作が完了するまで待つ必要がありません。
IO 集中型タスク (I/O バウンド) とは、ファイルの読み取りと書き込み、ネットワーク送信、データベース クエリなど、完了するために多数の I/O 操作を必要とするタスクを指します。この場合、システムの CPU パフォーマンスはハードディスクやメモリよりもはるかに優れており、このとき、CPU は I/O 操作 (ハードディスクの読み取りおよび書き込みなど) の完了を待機していることが多く、 CPU 負荷は高くありません。I/O 集中型のタスクでは、ほとんどの時間は I/O 操作の完了を待つのに費やされますが、CPU 使用率は比較的低くなります。実際のアプリケーションでは、さまざまな種類のタスクに応じて、適切なコンピュータ構成とアルゴリズムの最適化戦略を選択する必要があります。CPU を集中的に使用するタスクの場合は、強力な CPU を選択して I/O 待ち時間をできるだけ短縮する必要があり、I/O を集中的に使用するタスクの場合は、高速なハードウェアを選択する必要があります。ディスクとネットワークデバイスをできるだけ合理的に設定し、CPU リソースを有効に活用します。
注: Python 言語はインタープリター型言語であるため、CPU を大量に使用するタスクはあまりサポートされていません。Python グローバル インタープリター (グローバル インタープリター ロック、GIL) のスレッドは一度に 1 つしか実行できないためです。複数のスレッドの場合、同じ実行の瞬間に Python バイトコードを同時に実行することはできません。(シリアルです)、https://blog.csdn.net/qq_44993593/article/details/129120146 を参照してください。
同時実行と並列処理の違いは何ですか?
並列 (Parallel): 並列とは、複数のタスクを同時に実行することであり、各タスクは独立して実行する独自のプロセッサまたはコアを持っています。
同時実行: 同時実行とは、同じ期間内で複数のタスクを実行することです。これらのタスクは実行に CPU タイム スライスを交互に使用するため、ユーザーは同時に実行されているように感じます。
個人的な理解:例えば、毎年新年の挨拶に親戚が同じ日にまとめてあなたの家に来て、新年の挨拶の途中でお互いに会わない(兼任)、新年の挨拶には親戚全員が一緒にあなたの家に来ます年頭のご挨拶(並列)。
仕事盗用アルゴリズムとは何ですか? 主にどのような問題を解決しますか?
ワークスチール アルゴリズムは、タスク スケジューリングのための同時プログラミング アルゴリズムです。このアルゴリズムは、マルチスレッド環境におけるタスク実行の負荷分散の問題を目的としています。各スレッドは独自のキューでタスクを実行します。これにより、スレッドのリソースが節約され、一部のタスクの待機によってスレッドがアイドル状態になるのを防ぐことができます。
原則: ワークスチールアルゴリズムは両端キュー (deque) に基づいており、各スレッドには独自のワークキューがあり、タスクの実行順序は先入れ先出し (FIFO) です。スレッドがタスクを実行する必要がある場合、スレッドは最後に追加されたタスクを独自のキューから取り出して処理します。スレッドのキューが空の場合、スレッドは他のスレッドのワーク キューに移動してタスクを盗み、実行します。盗まれたタスクは通常、他のスレッド キューの先頭 (先頭) タスクであり、競合と競合を効果的に減らすことができます。スレッド間の競合をロックし、並列処理速度を向上させます。
アドバンテージ:
CPU リソースを効率的に利用する能力。
マルチコアプロセッサのパフォーマンスを最大限に活用します。
同時に、一部のタスクの待機によってスレッドがアイドル状態になるのを防ぐこともできます。
欠点:
タスクが盗まれる回数が増えるほど、スレッド間の負荷バランスを保証することが難しくなります。
さらに、タスクの並列性が低い場合、タスクのスチールによりオーバーヘッドが追加され、プログラムのパフォーマンスが低下する可能性があります。
ワークスチールアルゴリズムの実装ロジックは、主に次のステップに分かれています。
各スレッドにはワーク キューがあり、タスクは先入れ先出し (FIFO) 順序で実行されます。
スレッドがタスクを実行する必要がある場合、スレッドは最後に追加されたタスクを自身のキューの最後から取り出して処理します。
スレッドのキューが空の場合、スレッドは他のスレッドの作業キューに移動して、実行するタスクを盗みます。ここで、タスクスチールの負荷バランスを確保するために、スレッドは適切なスチールオブジェクトを選択する必要があることに注意してください。
スチールタスクは通常、他のスレッドキューの先頭 (キューヘッド) から実行されます。スレッドが別のスレッドのキューからタスクを盗むことに成功すると、そのタスクがすぐに実行されます。
タスクの実行中に、スレッドが新しいサブタスクを生成する場合があります。これらのサブタスクは、ロック競合を避けるために、他のスレッドのキューに直接送信されるのではなく、スレッドのローカル作業キューに配置されます。
タスクの実行中、スレッドは自身のローカル キューと他のスレッドのキューを常にチェックして、タスクの効率的な実行と負荷分散を確保します。
すべてのタスクが完了すると、スレッドは終了します。
ForkJoinの基本的な使い方
クラス図
クラスの説明:
ForkJoinTask は Java 並行プログラミングのクラスで、「分割統治」の考え方に基づき、「作業盗用」アルゴリズムを組み合わせた並列処理フレームワークです。
java.util.concurrent パッケージの ForkJoinTask は、具体的なタスクを作成するために継承する必要がある抽象クラスです。サブタスクを分割し、マルチスレッドを使用してこれらのタスクを並列実行し、結果をマージして最終的にタスク全体の結果を取得できます。
その中で、一般的に使用されるサブクラスには次のものがあります。 =
RecursiveAction: 結果を返さないタスク用。
RecursiveTask: 結果を返すタスクに使用されます。
タスクを実行するとき、ForkJoinPool はタスクを複数の小さなタスクに分割し、各スレッドは小さなタスクの 1 つを実行します。スレッドが自身のタスクの実行を終了すると、他のスレッドのキュー内のタスクを「盗んで」実行することができます。 CPU 使用率と同時実行効率を向上させるため。
従来のマルチスレッド プログラミングと比較して、ForkJoinTask を使用すると、CPU をより効率的に利用し、スレッド間の競合を減らし、プログラムのパフォーマンスを向上させることができます。
/**
*
* 功能描述:
*
* @param: 通过fork/join 进行求合计算
* @return:
* @auther: csh
* @date: 2023/4/17 9:52 下午
*/
public class ArraySum extends RecursiveTask<Long> {
private static final int THRESHOLD = 1000; // 阈值,当数组大小小于该值时不再进行拆分
private long[] arr;
private int start;
private int end;
public ArraySum(long[] arr, int start, int end) {
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) { // 如果数组大小小于阈值,直接计算
long sum = 0L;
for (int i = start; i < end; i++) {
sum += arr[i];
}
return sum;
} else { // 如果数组大小大于阈值,拆分为两个任务并执行
int mid = (start + end) / 2;
ArraySum left = new ArraySum(arr, start, mid);
ArraySum right = new ArraySum(arr, mid, end);
left.fork();
right.fork();
return left.join() + right.join();
}
}
public static void main(String[] args) {
int N = 100000;
long[] arr = new long[N];
for (int i = 0; i < N; i++) {
arr[i] = i;
}
ForkJoinPool pool = new ForkJoinPool();
long sum = pool.invoke(new ArraySum(arr, 0, arr.length));
System.out.println("累加起来的结果是: " + sum);
}
}
結果
相加起来的结果是: 4999950000
フォーク/ジョインのソースコード学習
ForkJoinTask は主に Unsafe クラスの CAS 操作を使用してタスクのステータスを更新します。タスクが完了したら、onCompletion(CountedCompleter caller) メソッドを呼び出して、タスクの依存タスクに通知するか、タスクを待機しているスレッドにシグナルを送信して、タスク結果のマージと配信を実現します。
属性:
static final int REOPR_SIGNAL: 表示任务的初始状态,即等待被执行。
static final int DONE_MASK: 任务完成状态的标识。
static final int NORMAL: 任务正常完成。
static final int CANCELLED: 任务被取消。
static final int EXCEPTIONAL: 任务发生异常。
volatile int status: 表示任务的状态,取值可能为 REOPR_SIGNAL、NORMAL、CANCELLED 或 EXCEPTIONAL 中的一个。
volatile ForkJoinTask<?> next: 指向下一个等待执行的任务。
volatile Thread runner: 执行该任务的线程。
final short statusFlags: 表示任务的状态及其他一些控制信息。
final short mode: 表示任务的运行模式。
Throwable exception: 任务执行过程中发生异常时,保存该异常对象。
方法:
public final void fork(): 将该任务加入到当前工作线程队列中,等待被执行。
public final boolean isDone(): 判断该任务是否已完成。
public final boolean cancel(boolean mayInterruptIfRunning): 取消该任务的执行。
public final void completeExceptionally(Throwable ex): 异常完成该任务,并将发生的异常传递给等待该任务的线程。
protected abstract void compute(): 子类必须实现的计算方法,用于执行具体的任务逻辑。
public final void quietlyCompleteRoot(): 安静地完成该任务,并通知等待该任务的线程。如果该任务是根任务,则将结果放到 ForkJoinPool 中的队列中。
public final int getQueuedTaskCount(): 获取等待执行的任务个数。
public final boolean isCancelled(): 判断该任务是否已取消。
public final boolean isCompletedAbnormally(): 判断该任务是否发生异常。
public final boolean isCompletedNormally(): 判断该任务是否正常完成。
public final Throwable getException(): 获取该任务发生的异常。
public final ForkJoinTask<V> submit(): 将该任务提交到 ForkJoinPool 中执行,并返回该任务的结果。
public final V invoke(): 在当前线程中执行该任务,并返回该任务的结果。
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2): 执行给定的两个任务,并等待这两个任务都完成。
public static <T> void invokeAll(ForkJoinTask<T>... tasks): 执行指定的一组任务,并等待所有任务都完成。
protected static void reportException(Throwable ex): 抛出给定的异常。
私有方法:
final int setCompletion(int completion): 原子性地将该任务的状态修改为完成状态,同时返回原状态值。
final int doExec(): 执行当前任务的 compute() 方法,并返回任务的状态值。
final boolean trySetSignal(): 尝试将当前任务的状态从新建转换为信号状态 REOPR_SIGNAL。
static void internalPropagateException(Throwable ex): 尝试将给定的异常对象抛出到外层任务。
package java.util.concurrent;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.reflect.Constructor;
//为抽象类必须被实现,实现Future
public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/** 状态:初始状态:status = SIGNAL
正常完成状态:status = NORMAL
取消状态:status = CANCELLED
异常状态:status = EXCEPTIONAL */
volatile int status; // accessed directly by pool and workers
static final int DONE_MASK = 0xf0000000; // 任务完成时的标识。
static final int NORMAL = 0xf0000000; // 正常任务状态。
static final int CANCELLED = 0xc0000000; // 取消状态。
static final int EXCEPTIONAL = 0x80000000; // 异常状态。
static final int SIGNAL = 0x00010000; // 初始状态 必须为 >= 1 << 16
static final int SMASK = 0x0000ffff; // 低位掩码,也是最大索引位
/**
* 原子性地将该任务的状态修改为完成状态,同时返回原状态值。
入参为状态
*/
private int setCompletion(int completion) {
for (int s;;) {
if ((s = status) < 0)
return s;
if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
if ((s >>> 16) != 0)
synchronized (this) { notifyAll(); }
return completion;
}
}
}
/**
*执行当前任务的 compute() 方法,并返回任务的状态值。
*/
final int doExec() {
int s; boolean completed;
//状态大于0
if ((s = status) >= 0) {
try {
//立即执行任务
completed = exec();
} catch (Throwable rex) {
return setExceptionalCompletion(rex);
}
//执行后状态判断
if (completed)
//设置状态为正常任务状态。
s = setCompletion(NORMAL);
}
//返回状态
return s;
}
/**
* 在等待该任务完成时,使用指定的超时时间来阻塞当前线程。
*/
final void internalWait(long timeout) {
int s;
//正常状态才继续
if ((s = status) >= 0 && // force completer to issue notify
//又是Unsafe 的cas来更改状态
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
//同步块
synchronized (this) {
//状态大于0 正常 等待timeout时间
if (status >= 0)
try { wait(timeout); } catch (InterruptedException ie) { }
else
//唤醒所有任务
notifyAll();
}
}
}
/**
* 阻止非工作线程,直到完成。
*/
private int externalAwaitDone() {
//判断类型获取池中的状态
int s = ((this instanceof CountedCompleter) ? // try helping
ForkJoinPool.common.externalHelpComplete(
(CountedCompleter<?>)this, 0) :
ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
//大于0证明不是初始化及已结束
if (s >= 0 && (s = status) >= 0) {
boolean interrupted = false;
do {
//通过循环方式进行cas设置锁
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0) {
try {
wait(0L);
} catch (InterruptedException ie) {
interrupted = true;
}
}
else
notifyAll();
}
}
} while ((s = status) >= 0);
//中断状态为true(有可能结束或异常了)
if (interrupted)
//进行当前线程中断
Thread.currentThread().interrupt();
}
//反回状态
return s;
}
/**
* 等待该任务完成,并允许在等待的过程中中断当前线程。
该方法通过调用 LockSupport.park(this) 方法来实现线程等待,如果当前线程被中断,则会抛出 InterruptedException 异常。
*/
private int externalInterruptibleAwaitDone() throws InterruptedException {
int s;
//中断线程成功 直接抛出
if (Thread.interrupted())
throw new InterruptedException();
//如果状态大于0 且 尝试通过线程池进行执行所有任务 证明正常
if ((s = status) >= 0 &&
(s = ((this instanceof CountedCompleter) ?
ForkJoinPool.common.externalHelpComplete(
(CountedCompleter<?>)this, 0) :
ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
0)) >= 0) {
//循环进行状态置为初始化
while ((s = status) >= 0) {
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
wait(0L);
else
notifyAll();
}
}
}
}
return s;
}
/**
* 等待该任务完成,并返回任务的状态。
在等待任务完成的过程中,使用自旋锁的方式不断地检查任务状态。
如果任务状态为完成状态,则返回该任务的状态;否则,使用 LockSupport.park(this) 方法挂起当前线程,并等待任务完成。
注意:这个方法在等待过程中由于使用了自旋锁和线程挂起的方式,因此可能会消耗大量的 CPU 资源。
*
*/
private int doJoin() {
//参数声名 状态:s 线程:t 工作线程:wt 工作队列:w
int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
//获取状态如果小于0 当前线程中断 否则进行结束
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();
}
/**
* 在当前线程中执行该任务,并返回任务的状态值(同上类似)
*/
private int doInvoke() {
int s; Thread t; ForkJoinWorkerThread wt;
return (s = doExec()) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(wt = (ForkJoinWorkerThread)t).pool.
awaitJoin(wt.workQueue, this, 0L) :
externalAwaitDone();
}
// Exception table support
//任务异常列表
private static final ExceptionNode[] exceptionTable;
//任务异常重入锁
private static final ReentrantLock exceptionTableLock;
//存放异常的实例
private static final ReferenceQueue<Object> exceptionTableRefQueue;
/**
* 异常表的固定容量。
*/
private static final int EXCEPTION_MAP_CAPACITY = 32;
//异常节点类实现
static final class ExceptionNode extends WeakReference<ForkJoinTask<?>> {
final Throwable ex;
ExceptionNode next;
final long thrower; // use id not ref to avoid weak cycles
final int hashCode; // store task hashCode before weak ref disappears
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) {
super(task, exceptionTableRefQueue);
this.ex = ex;
this.next = next;
this.thrower = Thread.currentThread().getId();
this.hashCode = System.identityHashCode(task);
}
}
/**
* 记录异常并设置状态。
*
* @return status on exit
*/
final int recordExceptionalCompletion(Throwable ex) {
int s;
//状态大于等于0
if ((s = status) >= 0) {
int h = System.identityHashCode(this);
//上锁
final ReentrantLock lock = exceptionTableLock;
lock.lock();
try {
expungeStaleExceptions();
ExceptionNode[] t = exceptionTable;
int i = h & (t.length - 1);
//循环创建
for (ExceptionNode e = t[i]; ; e = e.next) {
if (e == null) {
t[i] = new ExceptionNode(this, ex, t[i]);
break;
}
if (e.get() == this) // already present
break;
}
} finally {
lock.unlock();
}
s = setCompletion(EXCEPTIONAL);
}
return s;
}
/**
* 记录异常并可能传播。
*
* @return status on exit
*/
private int setExceptionalCompletion(Throwable ex) {
int s = recordExceptionalCompletion(ex);
if ((s & DONE_MASK) == EXCEPTIONAL)
internalPropagateException(ex);
return s;
}
/**
* Hook for exception propagation support for tasks with completers.
*/
void internalPropagateException(Throwable ex) {
}
/**
* 取消,忽略取消引发的任何异常。
*/
static final void cancelIgnoringExceptions(ForkJoinTask<?> t) {
if (t != null && t.status >= 0) {
try {
//取消
t.cancel(false);
} catch (Throwable ignore) {
}
}
}
/**
* 删除异常节点并清除状态。
*/
private void clearExceptionalCompletion() {
int h = System.identityHashCode(this);
final ReentrantLock lock = exceptionTableLock;
//上锁
lock.lock();
try {
ExceptionNode[] t = exceptionTable;
int i = h & (t.length - 1);
ExceptionNode e = t[i];
ExceptionNode pred = null;
//循环处理
while (e != null) {
ExceptionNode next = e.next;
if (e.get() == this) {
if (pred == null)
t[i] = next;
else
pred.next = next;
break;
}
pred = e;
e = next;
}
expungeStaleExceptions();
status = 0;
} finally {
//释放锁
lock.unlock();
}
}
//获取异常
private Throwable getThrowableException() {
//不是异常直接返回空
if ((status & DONE_MASK) != EXCEPTIONAL)
return null;
//获取哈希code
int h = System.identityHashCode(this);
ExceptionNode e;
//上锁
final ReentrantLock lock = exceptionTableLock;
lock.lock();
try {
//删除过期的引用
expungeStaleExceptions();
ExceptionNode[] t = exceptionTable;
e = t[h & (t.length - 1)];
while (e != null && e.get() != this)
e = e.next;
} finally {
lock.unlock();
}
Throwable ex;
if (e == null || (ex = e.ex) == null)
return null;
if (e.thrower != Thread.currentThread().getId()) {
Class<? extends Throwable> ec = ex.getClass();
try {
Constructor<?> noArgCtor = null;
Constructor<?>[] cs = ec.getConstructors();// public ctors only
for (int i = 0; i < cs.length; ++i) {
Constructor<?> c = cs[i];
Class<?>[] ps = c.getParameterTypes();
if (ps.length == 0)
noArgCtor = c;
else if (ps.length == 1 && ps[0] == Throwable.class) {
Throwable wx = (Throwable)c.newInstance(ex);
return (wx == null) ? ex : wx;
}
}
if (noArgCtor != null) {
Throwable wx = (Throwable)(noArgCtor.newInstance());
if (wx != null) {
wx.initCause(ex);
return wx;
}
}
} catch (Exception ignore) {
}
}
return ex;
}
/**
* 删除过期引用的实现方法
*/
private static void expungeStaleExceptions() {
//循环筛选
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
if (x instanceof ExceptionNode) {
int hashCode = ((ExceptionNode)x).hashCode;
ExceptionNode[] t = exceptionTable;
int i = hashCode & (t.length - 1);
ExceptionNode e = t[i];
ExceptionNode pred = null;
while (e != null) {
ExceptionNode next = e.next;
if (e == x) {
if (pred == null)
t[i] = next;
else
pred.next = next;
break;
}
pred = e;
e = next;
}
}
}
}
/**
* 轮询过时的引用并将其删除(带锁)
*/
static final void helpExpungeStaleExceptions() {
final ReentrantLock lock = exceptionTableLock;
if (lock.tryLock()) {
try {
//调用上面的方法
expungeStaleExceptions();
} finally {
lock.unlock();
}
}
}
/**
* 重新抛出异常的方法
*/
static void rethrow(Throwable ex) {
if (ex != null)
ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
}
/**
* The sneaky part of sneaky throw, relying on generics
* limitations to evade compiler complaints about rethrowing
* unchecked exceptions
*/
@SuppressWarnings("unchecked") static <T extends Throwable>
void uncheckedThrow(Throwable t) throws T {
throw (T)t; // rely on vacuous cast
}
/**
* 根据s的不同抛出不同的异常
*/
private void reportException(int s) {
if (s == CANCELLED)
throw new CancellationException();
if (s == EXCEPTIONAL)
rethrow(getThrowableException());
}
// public methods
/**
* 将该任务加入到当前工作线程队列中,等待被执行。
*/
public final ForkJoinTask<V> fork() {
Thread t;
//获取当前线程 判断是否为ForkJoinWorkerThread类型,是的话加入工作队列
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this);
else
//不是则加入工作池队列
ForkJoinPool.common.externalPush(this);
return this;
}
/**
*返回计算的结果
注意:此方法异常会导致中断
*/
public final V join() {
int s;
if ((s = doJoin() & DONE_MASK) != NORMAL)
reportException(s);
//返回计算结果
return getRawResult();
}
/**
* 在当前线程中执行该任务,并返回该任务的结果。
*
* 返回计算结果
*/
public final V invoke() {
int s;
if ((s = doInvoke() & DONE_MASK) != NORMAL)
reportException(s);
return getRawResult();
}
/**
* 执行给定的两个任务,并等待这两个任务都完成。
*/
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
int s1, s2;
t2.fork();
if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
t1.reportException(s1);
if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
t2.reportException(s2);
}
/**
* 执行指定的一组任务,并等待所有任务都完成。
*/
public static void invokeAll(ForkJoinTask<?>... tasks) {
Throwable ex = null;
//获取最后一个节点下标
int last = tasks.length - 1;
//倒序
for (int i = last; i >= 0; --i) {
//获取对象
ForkJoinTask<?> t = tasks[i];
//为空 进行抛出空指针异常
if (t == null) {
if (ex == null)
ex = new NullPointerException();
}
//不为空 进行加入队列
else if (i != 0)
t.fork();
//执行并返回结果 如果状态为NORMAL 且 ex为空抛出异常
else if (t.doInvoke() < NORMAL && ex == null)
ex = t.getException();
}
//自增进行
for (int i = 1; i <= last; ++i) {
ForkJoinTask<?> t = tasks[i];
if (t != null) {
if (ex != null)
t.cancel(false);
//加入执行队列
else if (t.doJoin() < NORMAL)
ex = t.getException();
}
}
//异常不为空则抛出异常
if (ex != null)
rethrow(ex);
}
//同上类似
public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
return tasks;
}
@SuppressWarnings("unchecked")
List<? extends ForkJoinTask<?>> ts =
(List<? extends ForkJoinTask<?>>) tasks;
Throwable ex = null;
int last = ts.size() - 1;
for (int i = last; i >= 0; --i) {
ForkJoinTask<?> t = ts.get(i);
if (t == null) {
if (ex == null)
ex = new NullPointerException();
}
else if (i != 0)
t.fork();
else if (t.doInvoke() < NORMAL && ex == null)
ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
ForkJoinTask<?> t = ts.get(i);
if (t != null) {
if (ex != null)
t.cancel(false);
else if (t.doJoin() < NORMAL)
ex = t.getException();
}
}
if (ex != null)
rethrow(ex);
return tasks;
}
//尝试取消此任务的执行。
public boolean cancel(boolean mayInterruptIfRunning) {
return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
}
//判断是否结束 true是 false否
public final boolean isDone() {
return status < 0;
}
// 判断该任务是否已取消。
public final boolean isCancelled() {
return (status & DONE_MASK) == CANCELLED;
}
/**
* 判断该任务是否发生异常。true是 false否
*/
public final boolean isCompletedAbnormally() {
return status < NORMAL;
}
/**
* 判断该任务是否正常完成。true是 false否
*/
public final boolean isCompletedNormally() {
return (status & DONE_MASK) == NORMAL;
}
/**
* 获取异常
public final Throwable getException() {
int s = status & DONE_MASK;
return ((s >= NORMAL) ? null :
(s == CANCELLED) ? new CancellationException() :
getThrowableException());
}
/**
* 异常完成该任务,并将发生的异常传递给等待该任务的线程。
*/
public void completeExceptionally(Throwable ex) {
setExceptionalCompletion((ex instanceof RuntimeException) ||
(ex instanceof Error) ? ex :
new RuntimeException(ex));
}
/**
*用于执行具体的任务逻辑。
*/
public void complete(V value) {
try {
setRawResult(value);
} catch (Throwable rex) {
setExceptionalCompletion(rex);
return;
}
setCompletion(NORMAL);
}
/**
* 在不设置值的情况下正常完成此任务
*
* @since 1.8
*/
public final void quietlyComplete() {
setCompletion(NORMAL);
}
/**等待计算完成,然后检索其结果。
*/
public final V get() throws InterruptedException, ExecutionException {
int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
doJoin() : externalInterruptibleAwaitDone();
Throwable ex;
if ((s &= DONE_MASK) == CANCELLED)
throw new CancellationException();
if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
throw new ExecutionException(ex);
return getRawResult();
}
/**
* 带超时的等待执行结束,获取结果
*/
public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
int s;
long nanos = unit.toNanos(timeout);
if (Thread.interrupted())
throw new InterruptedException();
if ((s = status) >= 0 && nanos > 0L) {
long d = System.nanoTime() + nanos;
long deadline = (d == 0L) ? 1L : d; // avoid 0
Thread t = Thread.currentThread();
if (t instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
s = wt.pool.awaitJoin(wt.workQueue, this, deadline);
}
else if ((s = ((this instanceof CountedCompleter) ?
ForkJoinPool.common.externalHelpComplete(
(CountedCompleter<?>)this, 0) :
ForkJoinPool.common.tryExternalUnpush(this) ?
doExec() : 0)) >= 0) {
long ns, ms; // measure in nanosecs, but wait in millisecs
while ((s = status) >= 0 &&
(ns = deadline - System.nanoTime()) > 0L) {
if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
wait(ms); // OK to throw InterruptedException
else
notifyAll();
}
}
}
}
}
if (s >= 0)
s = status;
if ((s &= DONE_MASK) != NORMAL) {
Throwable ex;
if (s == CANCELLED)
throw new CancellationException();
if (s != EXCEPTIONAL)
throw new TimeoutException();
if ((ex = getThrowableException()) != null)
throw new ExecutionException(ex);
}
return getRawResult();
}
/**
* 加入此任务,而不返回其结果或引发其异常。
*/
public final void quietlyJoin() {
doJoin();
}
/**
*开始执行此任务,并在必要时等待其完成,而不返回其结果或引发其异常。
*/
public final void quietlyInvoke() {
doInvoke();
}
/**
* 用于等待所有正在执行的任务完成。
*/
public static void helpQuiesce() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
wt.pool.helpQuiescePool(wt.workQueue);
}
else
ForkJoinPool.quiesceCommonPool();
}
/**
* 重置此任务的内部簿记状态,允许后续
*/
public void reinitialize() {
if ((status & DONE_MASK) == EXCEPTIONAL)
clearExceptionalCompletion();
else
status = 0;
}
/**
* 获取任务线程池
*/
public static ForkJoinPool getPool() {
Thread t = Thread.currentThread();
return (t instanceof ForkJoinWorkerThread) ?
((ForkJoinWorkerThread) t).pool : null;
}
/**
*判断当前是否为线程池执行,如果是则返回true
*/
public static boolean inForkJoinPool() {
return Thread.currentThread() instanceof ForkJoinWorkerThread;
}
/**
* 尝试取消执行的任务
*/
public boolean tryUnfork() {
Thread t;
//获取当前线程 判断在池中还是队列,然后进行取消
return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
((ForkJoinWorkerThread)t).workQueue.tryUnpush(this) :
ForkJoinPool.common.tryExternalUnpush(this));
}
/**
* 返回当前任务的队列计数(排队数)
*/
public static int getQueuedTaskCount() {
Thread t; ForkJoinPool.WorkQueue q;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
q = ((ForkJoinWorkerThread)t).workQueue;
else
q = ForkJoinPool.commonSubmitterQueue();
return (q == null) ? 0 : q.queueSize();
}
/**
* 获取线程池中的排队数
*
* @return the surplus number of tasks, which may be negative
*/
public static int getSurplusQueuedTaskCount() {
return ForkJoinPool.getSurplusQueuedTaskCount();
}
// Extension methods
/**
* 返回的结果(即使此任务异常完成)或 {@code null}(如果此任务未知已完成)
*
* @return the result, or {@code null} if not completed
*/
public abstract V getRawResult();
/**
* Forces the given value to be returned as a result. This method
* is designed to support extensions, and should not in general be
* called otherwise.
*
* @param value the value
*/
protected abstract void setRawResult(V value);
/**
* 抽象的执行方法 (子类需要实现)
*/
protected abstract boolean exec();
/**
* 获取当前排队中的任务
*/
protected static ForkJoinTask<?> peekNextLocalTask() {
Thread t; ForkJoinPool.WorkQueue q;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
q = ((ForkJoinWorkerThread)t).workQueue;
else
q = ForkJoinPool.commonSubmitterQueue();
return (q == null) ? null : q.peek();
}
/**
* 用于从当前线程绑定的工作队列中获取下一个待执行的任务。
*/
protected static ForkJoinTask<?> pollNextLocalTask() {
Thread t;
return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
((ForkJoinWorkerThread)t).workQueue.nextLocalTask() :
null;
}
/**
* 用于从当前线程绑定的工作队列和共享队列中获取下一个待执行的任务。
*/
protected static ForkJoinTask<?> pollTask() {
Thread t; ForkJoinWorkerThread wt;
return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(wt = (ForkJoinWorkerThread)t).pool.nextTaskFor(wt.workQueue) :
null;
}
// tag operations
/**
* 获取当前状态
* @since 1.8
*/
public final short getForkJoinTaskTag() {
return (short)status;
}
/**
* 以原子方式设置此任务的标记值。
*/
public final short setForkJoinTaskTag(short tag) {
for (int s;;) {
if (U.compareAndSwapInt(this, STATUS, s = status,
(s & ~SMASK) | (tag & SMASK)))
return (short)s;
}
}
/**
*以原子方式有条件地设置此任务的标记值。
*/
public final boolean compareAndSetForkJoinTaskTag(short e, short tag) {
for (int s;;) {
if ((short)(s = status) != e)
return false;
if (U.compareAndSwapInt(this, STATUS, s,
(s & ~SMASK) | (tag & SMASK)))
return true;
}
}
/**
* 适配器类
*/
static final class AdaptedRunnable<T> extends ForkJoinTask<T>
implements RunnableFuture<T> {
//用于存储被适配的 Runnable 对象。
final Runnable runnable;
T result;
//构造方法 线程和结果为入参
AdaptedRunnable(Runnable runnable, T result) {
if (runnable == null) throw new NullPointerException();
this.runnable = runnable;
this.result = result; // OK to set this even before completion
}
//获取执行结果方法
public final T getRawResult() { return result; }
//设置执行结果方法
public final void setRawResult(T v) { result = v; }
//执行返回true
public final boolean exec() { runnable.run(); return true; }
//运行无返回
public final void run() { invoke(); }
private static final long serialVersionUID = 5232453952276885070L;
}
/**
* 有返回的适配器类 与上面的类似,唯一的区别是没有返回
*/
static final class AdaptedRunnableAction extends ForkJoinTask<Void>
implements RunnableFuture<Void> {
final Runnable runnable;
AdaptedRunnableAction(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
this.runnable = runnable;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
private static final long serialVersionUID = 5232453952276885070L;
}
/**
* 同上类似(带异常)
*/
static final class RunnableExecuteAction extends ForkJoinTask<Void> {
final Runnable runnable;
RunnableExecuteAction(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
this.runnable = runnable;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
void internalPropagateException(Throwable ex) {
rethrow(ex); // rethrow outside exec() catches.
}
private static final long serialVersionUID = 5232453952276885070L;
}
/**
* 适配器
*/
static final class AdaptedCallable<T> extends ForkJoinTask<T>
implements RunnableFuture<T> {
final Callable<? extends T> callable;
T result;
AdaptedCallable(Callable<? extends T> callable) {
if (callable == null) throw new NullPointerException();
this.callable = callable;
}
public final T getRawResult() { return result; }
public final void setRawResult(T v) { result = v; }
public final boolean exec() {
try {
result = callable.call();
return true;
} catch (Error err) {
throw err;
} catch (RuntimeException rex) {
throw rex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public final void run() { invoke(); }
private static final long serialVersionUID = 2838392045355241008L;
}
/**
* 返回一个新的AdaptedRunnableAction适配器
*/
public static ForkJoinTask<?> adapt(Runnable runnable) {
return new AdaptedRunnableAction(runnable);
}
/**
* 返回一个AdaptedRunnable适配器
*/
public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) {
return new AdaptedRunnable<T>(runnable, result);
}
/**
* 返回一个AdaptedCallable适配器
*/
public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
return new AdaptedCallable<T>(callable);
}
// Serialization support
private static final long serialVersionUID = -7721805057305804111L;
/**
* 输入对象流
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeObject(getException());
}
/**
* 读文件
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
Object ex = s.readObject();
if (ex != null)
setExceptionalCompletion((Throwable)ex);
}
// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final long STATUS;
//初始化静态代码块
static {
//实例会异常锁
exceptionTableLock = new ReentrantLock();
//实例会引用对象
exceptionTableRefQueue = new ReferenceQueue<Object>();
//实例化异常节点对象
exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
try {
//实例化unsafe
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = ForkJoinTask.class;
STATUS = U.objectFieldOffset
(k.getDeclaredField("status"));
} catch (Exception e) {
throw new Error(e);
}
}
}
やっと
残念なことに、これまでのところ、多くのプロジェクトや多くの同僚や友人が開発を行っている中で、この ForkJoin はめったに使用されず、そのほとんどは依然として CURD のままです。残念ですが、実際には、データベース クエリの最適化、画像処理ForkJoin の並列処理機能により、機械学習、ビッグデータ処理などのシナリオを実現できます。もちろん、この ForkJoin には非常に多くの使用法があり、自分で理解することができます。