血液背景レッスン:インベントリデータ移行のスレッドプールを使用しませんが、データ移行の数が失敗し、常にありますが、例外ログを印刷
殺人の原因
私はそれを聞いてparallelStream
、毎日開発するので、平行な流れが良いことでstream
、移行プログラムを記述する必要がちょうど適用できるシリアルストリームの詳細なシーン、それはすぐに*それをインストール持っていない、そして今すぐインストールしていない、とき。私はまた、ウィットを知っているプールは、各プロセッサのためのスレッドを割り当てる参加/フォーク、プールはデフォルトで、すべての並列ストリームによって共有されているこれらの機能を完了するために、プールに参加する/、JVMの背景に共通のフォークの使用を、対応しますこの問題を回避するには、として、独自のスレッドプールを作成することです
ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
pool.submit(() -> {
list.parallelStream().collect(Collectors.toList());
});
复制代码
だからここからそれが植え地雷。
提出または実行
public static void main(String[] args) throws InterruptedException, ExecutionException {
final ExecutorService pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
List<Integer> list = Lists.newArrayList(1, 2, 3, null);
//1.使用submit
pool.submit(() -> {
list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
});
TimeUnit.SECONDS.sleep(3);
//2.使用 execute
pool.execute(() -> {
list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
});
//3.使用submit,调用get()
pool.submit(() -> {
list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
}).get();
TimeUnit.SECONDS.sleep(3);
}
复制代码
上記のユースケースで実行するために、読者、あなたは別の見つけるsubmit
方法をして、エラーログを印刷し使用することはありませんexecute
、エラー・ログをプリントアウトする方法を、しかしするsubmit
に戻りFutureJoinTask
呼び出し側のget()
メソッドは例外をスローします。このように真実、ダーティデータのいくつかのバッチに存在するデータは、NULL値は、null値は、例外が発生した際に横断するが、例外ログにsubmit
ライブプロセスをキャッチするために、ではない(痛い)を印刷、ありますキャッチされない例外は、返されたクラスの結果にパッケージ化されFutureJoinTask
、そして再びスローされませんでした。
あなたは非同期に結果を返さない場合は、使用しないでくださいsubmit
方法を
結論は最初、私は無地だと思い、ミスを犯したsubmit
とexecute
の違いは、単に非同期結果に復帰され、ステップは結果を返しませんが、事実は残酷です。ではsubmit()
ロジックは、非同期タスクがスローされた例外をキャッチすることになります含まれている必要がありますが、不適切な使用のためには、例外が再スローされません原因。
今、質問をするForkJoinPool#submit()
見返りに、ForkJoinTask
あなたは非同期タスクの結果を得ることができ、今で非同期例外がスローされていることを、私たちは、タスクの結果がどのようになります取得しようか?私たちは、直接見ForkJoinTask#get()
ソース。
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();
//这里可以直接看到,异步任务出现异常会在调用get()获取结果的时候,会被包装成ExecutionException再次抛出
if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
throw new ExecutionException(ex);
return getRawResult();
}
复制代码
GET()の結果を得るために呼び出すときに、非同期タスクが異常になり、中に包装されExecutionException
、再び投げ、それがキャプチャされた場合の例外はありますか?同じまま、スレッドのすべてのスレッドが書き直されなければならThread#run()
に投稿された方法で、ForkJoinPool
スレッドがにパッケージ化されますForkJoinWorkerThread
ので、我々は見てForkJoinWorkerThread#run()
の実装。
public void run() {
if (workQueue.array == null) { // only run once
Throwable exception = null;
try {
onStart();
pool.runWorker(workQueue);
} catch (Throwable ex) {
//出现异常,捕获,再次抛出会在调用ForkJoinTask#get()的时候
exception = ex;
} finally {
try {
onTermination(exception);
} catch (Throwable ex) {
if (exception == null)
exception = ex;
} finally {
pool.deregisterWorker(this, exception);
}
}
}
}
复制代码
上記の分析をベースにForkJoinPool
、スレッドプールのすべてではないsubmit
とexecute
実現は、このようにしている、私たちは多くの場合、スレッドプールを使用するThreadPoolThread
ことになるものを達成するために、同じアイディアは、我々は必要に配信見つけるために、ThreadPoolThread
最終的にパッケージ化されます非同期タスクこれはThread
サブクラスや実装java.lang.Runnable#run
、答えはjava.util.concurrent.FutureTask
public void run() {
...
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
//捕获异常
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
}
....
}
复制代码
概要
java.util.concurrent.ExecutorService#submit(java.lang.Runnable)
なぜそこに、このようなスレッドプールの設定は、実際には、私たちの思考は、スレッドプールに限定されるものではなく、ですが、上の非同期であり、それは異常な結果であるかどうか、非同期タスクの結果を取得し、FutureTask
JDKとして同時実行ツールは、提供は我々は非常に良い答え、与えられた実行中の非同期タスクがスローに表示された場合も、非同期異常な結果に属する、結果非同期タスクを取得し、異常は、その後、結果を取得する作業は、例外が再パッケージ化されます
著者:plzは私を呼び出す赤いスカーフ
このブログを転載へようこそますが、この節で宣言され、著者の同意なしに保持され、それ以外の記事のページの見かけ上の位置にある元の接続、法的責任を追及する権利を与えられなければなりません。コードワードは容易ではない、私の執筆のあなたのポイントを称賛最大の力であります