使用受管理的阻止在ForkJoinPool中导致饥饿
在我的应用程序中,我以不同的速率向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
给内部调用externalPush
方法的ForkJoinPool
:
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
方法。