私のアプリケーションでは、2 種類のタスクを commonPool に異なるレートで送信しています。
タスク1:
ForkJoinPool.managedBlock(
//...
Uninterruptibles.putUninterruptibly(blockingQueueQithMaxSize50, "a")
//...
);
タスク-2:
List<String> list = Lists.newLinkedList();
ForkJoinPool.managedBlock(
//...
Queues.drainUninterruptibly(blockingQueueWithMaxSize50, list, 1, 1, SECONDS);
//...
);
一部のシナリオでは、タイプタスク 1のタスクがプールにサブミットされる速度が高すぎて、blockingQueue がいっぱいになると、タイプタスク 1のタスクを実行しているすべてのスレッドが put でブロックされます (スレッド数52くらいです)。しかし、まだプールにサブミットされているタイプtask-1およびtask-2の新しいタスクは、プール内で新しいワーカーが生成されないため、後続のすべてのタスクがワーク キューにエンキューされ、飢餓とデッドロックにつながります。アプリがフリーズする原因。
ここで私が間違っていることを理解するのを手伝ってもらえますか?
掘り下げた後、これらを見つけました:
しかし、このバグはJava 7自体で修正されたようです。
環境:
- JDK: オラクル-j2sdk1.8 | 1.8.0+アップデート20
- アーチ: amd64
- OS: Debian Wheezy
共通プール構成:
- 利用可能なプロセッサ = 2
- つまり、並列度 = 1
- 他のすべての構成はデフォルトです
更新 1
いくつかの詳細情報:
内部呼び出しメソッドにsubmit
ランナブルを設定しています:ForkJoinPool
externalPush
final void externalPush(ForkJoinTask<?> task) {
WorkQueue q; int m, s, n, am; ForkJoinTask<?>[] a;
int r = ThreadLocalRandom.getProbe();
int ps = plock;
WorkQueue[] ws = workQueues;
if (ps > 0 && ws != null && (m = (ws.length - 1)) >= 0 &&
(q = ws[m & r & SQMASK]) != null && r != 0 &&
U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock
if ((a = q.array) != null &&
(am = a.length - 1) > (n = (s = q.top) - q.base)) {
int j = ((am & s) << ASHIFT) + ABASE;
U.putOrderedObject(a, j, task);
q.top = s + 1; // push on to deque
q.qlock = 0;
if (n <= 1)
signalWork(ws, q);
return;
}
q.qlock = 0;
}
fullExternalPush(task);
}
リモートデバッグを行うと、実行が到達します
q.top = s + 1; // push on to deque
q.qlock = 0;
if (n <= 1)
signalWork(ws, q);
return;
しかし、n は非常に大きく、1 以下ではないため、内部的signalWork
にメソッドを呼び出すメソッドは呼び出されていませんtryAddWorker
。