ForkJoinPool中的饥饿与托管阻止

时间:2016-05-12 09:16:47

标签: java multithreading 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:

  • JDK:oracle-j2sdk1.8 | 1.8.0 + update20
  • Arch:amd64
  • OS:Debian Wheezy

公共池配置:

  • 可用处理器= 2
  • 这意味着并行度= 1
  • 所有其他配置都是默认的

更新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方法。

0 个答案:

没有答案