在我的应用程序中,我以不同的速率向commonPool提交两种任务。
任务-1:
ForkJoinPool.managedBlock(
//...
Uninterruptibles.putUninterruptibly(blockingQueueQithMaxSize50, "a")
//...
);
任务-2:
List<String> list = Lists.newLinkedList();
ForkJoinPool.managedBlock(
//...
Queues.drainUninterruptibly(blockingQueueWithMaxSize50, list, 1, 1, SECONDS);
//...
);
在某些情况下,当 task-1 类型的任务提交到池的速率太高,并且blockingQueue已满时,所有线程都运行类型的任务task-1 在put上阻塞(线程数约为52)。但是,仍然提交到池中的 task-1 和 task-2 类型的新任务不会导致在池中生成新工作程序而导致所有后续任务将被排入工作队列,导致饥饿和僵局导致应用程序冻结。
有人可以帮助我理解我在这里做错了吗?
经过一番挖掘,我发现了这些:
但看起来这个bug在java 7中已得到修复。
ENV:
公共池配置:
更新1
更多信息:
我submit
将runnable转到内部调用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
方法。