当前位置: 首页 > 知识库问答 >
问题:

ExecutorService:当在线程中执行同步屏障时,如何防止线程饥饿

慕宏峻
2023-03-14

我有一个情况,我很难找到一个干净的解决方案。我会尽量详细解释的。

我有一个树状的结构:

NODE A
    NODE A.1
    NODE A.2
        NODE A.2.a
        NODE A.2.b
    NODE A.3
        NODE A.3.a
        NODE A.3.b
        NODE A.3.c
NODE B
    NODE B.1
    NODE B.2

我需要处理根节点:

 public void process(final Node node) { ... }
- some database queries
- the process of all children of these nodes

换句话说,一旦处理了node.2.anode.2.b,就可以处理node.2。我以递归的方式处理节点,没有什么壮观的。

到目前为止,一切都很好。现在我要声明一个全局执行器服务,它有固定数量的线程。我想并行处理一个节点的子节点。因此,node.2.anode.2.b可以在各自的线程中进行处理。代码如下所示:

// global executor service, shared between all process(Node) calls
final ExecutorService service = Executors.newFixedThreadPool(4);

public void process(final Node node) {
    // database queries
    ...

    // wait for children to be processed
    final CountDownLatch latch = new CountDownLatch(node.children().size());

    for (final Node child : node.children()) {
        service.execute(() -> {
             process(child);
             latch.countDown();
        });
    }
    latch.await();
}

这里的问题是:当达到一定深度时,锁存器中将停止所有线程。await()。我们已经到了缺线的情况。

共有1个答案

葛俊
2023-03-14

从技术上来说,这是一个僵局。我们首先认为死锁是当两个或多个进程等待锁时,但在这种情况下,线程是相互等待的。有趣的是,这是一种产生自我僵局的奇怪野兽的方式。如果您有一个线程池,它将提交任务并等待它们,但从不执行,因为它在等待自己完成以执行它们!

标准答案被称为“工作窃取线程池”。我遇到了完全相同的问题,没有这部分词汇表,我花了很长时间才能找到任何关于我快速得出的结论的信息,这是在完全并发递归中执行的任何递归算法中的一个常见问题。

好的,这是它如何工作的草图。用一个技巧创建一个相当标准的线程池。当一个线程到达一个点时,如果没有排队项的结果,它就不能继续下去,检查该项是否由另一个线程启动,如果它没有在当前线程中执行它(而不是等待),否则等待执行该项的线程完成它。

 类似资料:
  • 问题内容: 我一直在尝试解决涉及使用wait()和notify()的线程通信的问题。基本上我有2个线程T1和T2,我希望它们按以下顺序执行 T1,T2,T1,T2 .....我该如何实现? 实际的问题:有两个线程T1-打印奇数(例如1-100),而T2-打印偶数(1-100)。现在,输出应为1,2,3,4,5,.... 100 问题答案: 您描述了生产者-消费者模式。 它是Java的实现,在许多J

  • 问题内容: 我的任务是按以下顺序创建线程:如果A开始->启动B和C,如果B开始->启动D。并以相反的顺序销毁它们如果D然后B。如果B和C然后A。它。我设法做到了,但我想还有更好的方法。你有什么建议吗? 在您发表评论后,我更改了代码,这非常简单。但是现在看起来“愚蠢”。我想更改if语句和实现的硬性,有什么建议吗?寻求建议,我正在与您一起学习。 这是我的新代码: 问题答案: 您的代码中存在一些缺陷,这

  • 我通过创建固定数量的线程来使用执行器服务来进行HTTP GET数据检索。 当Tomcat停止时,我们会出现以下错误: 严重:web应用程序[/viewer]似乎已启动名为[ThreadExecutor_51616156]的线程,但未能停止该线程。这很可能会造成内存泄漏。 这是真的吗?在没有这些服务错误的情况下,如何正确停止tomcat。

  • 问题内容: 如果我在同步块内创建一个新线程,该块是否将保持锁定状态,直到线程执行完成为止?如果没有,那么直到什么时候才能保持锁定状态? 问题答案: 如果代码d具有新创建的线程,则它将保持锁定,从而等待它完成。由于没有锁,因此在调用完成后将不释放锁定。

  • 线程n:usern:task1->task2->Task3,usern:task1->task2->Task3,usern:task1->task2->Task3,... 然而,我还不知道如何做到这一点。每次我运行测试时,所有线程似乎都在迭代CSV文件并混合用户时选择用户,直到同时在两个不同的线程上找到一个用户。 像这样: 线程n:usern:task1->task2->Task3,...,use