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

ThreadPoolExecutor与ForkJoinPool:窃取子任务

越英范
2023-03-14

从java文档,

ForkJoinPool不同于其他类型的ExecutorService,主要是因为它采用了工作窃取:池中的所有线程都试图查找并执行其他活动任务创建的子任务(如果不存在,则最终阻塞等待工作)。

当大多数任务产生其他子任务时(就像大多数ForkJoinTasks一样),这可以实现高效处理。当在构造函数中将asyncMode设置为true时,ForkJoinPools也可能适合用于从未加入的事件样式任务。

在阅读了下面的ForkJoinPool示例之后,和ThreadPoolExecutor不同,我并没有看到设置队列大小的参数。我不知道ForkJoinPool是如何偷窃的。

//creating the ThreadPoolExecutor

ThreadPoolExecutor executorPool = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, 
new ArrayBlockingQueue<Runnable>(3000), threadFactory, rejectionHandler);

假设我创建了ThreadPoolExecutor,其中包含10个线程,并提交了3000个可调用任务。这些线程如何共享子任务的执行负载?

对于相同的用例,ForkJoin池的行为如何不同?

共有2个答案

都浩淼
2023-03-14

在ForkJoinPool中,有两种队列—一种是提交任务时基本使用的队列,另一种是特定于线程的队列(即每个线程一个)。从ForkJoinTask中,您可以调用新任务(通常是问题的一部分)。

这些新任务不是提供给池队列,而是提供给特定于线程的队列。因此,它们优先于池1,就像您在同一个任务中完成了所有工作一样。此外,调用器任务似乎被阻止以完成子任务。

实际上,“阻塞时间”用于消耗子任务。当其中一个线程被工作淹没时,让其他线程“游手好闲”将是愚蠢的。所以,“偷工减料”就发生了。

超越。为了提高效率,“偷工减料”将任务从相反的界限中抽取。这大大减少了队列写入的争用。

总是在效率上,最好只将问题拆分为两个子任务,让子任务一次又一次地拆分。即使您知道问题也必须直接拆分为N部分。这是因为“工作窃取”需要并发写入共享资源,因此限制其激活和争用!

楚嘉纳
2023-03-14

如果您预先有3000个任务,并且它们不会产生其他任务,那么两者的行为不会有很大不同:对于10个线程,一次将运行10个任务,直到它们全部完成。

ForkJoinPool设计用于一个或几个任务开始,但这些任务知道如何将自己拆分为子任务的情况。在这种情况下,ForkJoinPool进行了优化,以允许任务检查处理线程的可用性,并适当地将其拆分。

 类似资料:
  • 问题内容: 我想通过一种方法将任务提交到ForkJoinPool中: 注意,我使用的是JDK 7。 在后台,它们被转换为ForkJoinTask对象。我知道,当将任务递归拆分为较小的任务时,ForkJoinPool是有效的。 题: 如果没有递归,偷窃工作是否仍可以在ForkJoinPool中进行? 在这种情况下值得吗? 更新1: 任务很小,可以不平衡。即使对于严格相等的任务,诸如上下文切换,线程调

  • 我试图理解工作窃取对递归任务的影响:工作窃取的一个优点是,当前的工作线程/线程可能会执行自己的生成任务;增加数据局部性。但是,在常见情况下,当工作线程加入其生成的任务时会发生什么?例如: 我认为这里当前线程会被阻塞,因此无法从自己的队列中获取工作,因此另一个工作人员将不得不窃取这些工作。这将否认工作窃取的局部优势。然而,根据维基百科(https://en.wikipedia.org/wiki/Wo

  • 问题内容: Java 5以Executor框架的形式引入了对线程池执行异步任务的支持,其核心是java.util.concurrent.ThreadPoolExecutor实现的线程池。Java 7以java.util.concurrent.ForkJoinPool的形式添加了备用线程池。 查看它们各自的API,ForkJoinPool在标准情况下提供了ThreadPoolExecutor功能的超

  • 在我的项目中,我正在构建一个Java的执行框架,它接收来自客户端的工作请求。工作(大小不同)被分解为一组任务,然后排队等待处理。有单独的队列来处理每种类型的任务,每个队列都与一个ThreadPool相关联。ThreadPools的配置方式使引擎的整体性能达到最佳。 这种设计有助于我们有效地平衡请求的负载,大型请求不会占用系统资源。然而,当一些队列为空并且它们各自的线程池闲置时,该解决方案有时会变得

  • 我对和的内部调度机制有点困惑。 同时,显示为不同的,因为它使用了工作窃取算法。如果我理解正确,它意味着一个线程可以从另一个线程窃取一些任务。 然而,我并不真正理解和中实现的机制之间的区别。从我的理解来看,两种机制都应该尽可能减少每个线程的空闲时间。 如果在的情况下,每个线程都有自己的队列,我会理解的。然而,情况并非如此,因为队列是由池的不同线程共享的。

  • 我已经实现了ThreadPoolExecutor来调用任务。而且,由于核心/队列大小的错误配置,任务似乎挂起在I/O上。我想拉出挂起的线程,以便队列中的其他线程开始执行。 有没有办法列出threadpoolexecutor中的线程并拉出挂起的线程?