我们遇到了一点问题。:)
我们要确保任何时候只有 N 个线程在做后台任务。为此,我们使用了一个固定的线程池执行器。它似乎工作正常。
然后我们发现了一个问题。假设你有一个类,它使用 executor 来做一些并行工作,然后它在 executor 线程中调用其他一些类,它也做一些并行工作,打算等待它。这是发生的事情:
- 主线程调用第一级方法。
- 这种方法认为它可以并行化为 16 个任务并将其工作拆分。
- 16 个任务提交给执行者。
- 主线程开始等待其任务完成。
- 假设有四个线程可用,前四个任务每个都被拾取并运行。所以队列中还有 12 个任务。
- 现在,其中一项任务调用了其他方法。
- 这种新方法认为它可以并行化为 2 个任务。假设这是并行合并排序的第一步或类似的事情。
- 2个任务提交给执行者。
- 该线程现在开始等待其任务完成。
哦哦。所以在这一点上,所有四个线程现在都在等待任务完成,但它们正在协作阻止实际运行这些任务的执行程序。
此问题的解决方案 1 如下:在向执行程序提交新任务时,如果我们已经在运行所有线程,并且我们已经在其中一个执行程序线程上运行,则内联运行任务。这工作了 10 个月,但现在我们遇到了问题。如果它正在提交的新任务仍然相对较大,那么您可能会遇到新任务阻止该方法将其他任务添加到队列中的情况,否则这些任务将能够被其他工作线程拾取。因此,当线程在线处理工作时,您会遇到巨大的延迟。
对于执行潜在无界的后台任务树的核心问题,是否有更好的解决方案?我知道 .NET 相当于 executor 服务具有某种从队列中窃取的内置能力,可以防止发生原始死锁问题,据我所知,这是一个理想的解决方案。但是在 Java 的土地上呢?