【问题标题】:ThreadPool does not run tasks in sequenceThreadPool 不按顺序运行任务
【发布时间】:2011-05-27 02:38:37
【问题描述】:

我正在使用Executor 框架,特别是Executors.newCachedThreadPool();
我有一个Runnables 的列表,例如100.
前 50 个,每个创建一个值(存储在列表中)供最后 50 个使用。
我想如果我按照它们在列表中的顺序通过executor.execute() 中的Runnables,它们将是 也以相同的顺序执行。
但这并没有发生。
这些任务似乎是按随机顺序执行的,它们是交错的,而不是按顺序执行的。
这是它应该如何工作的吗?有什么办法可以解决这个问题?

谢谢

【问题讨论】:

  • Executors.execute() 不做任何排序保证。工作人员将按顺序从队列中取出,但可以在完成前的任何时间进行上下文切换。因此,如果您有 50 个线程,则列表最多可以跳过 50 个任务。
  • 只有一个线程才能保证订单。否则下一个空闲线程将启动下一个可用任务。

标签: java multithreading executorservice executor


【解决方案1】:

您需要分两批提交作业,或者创建明确的“先发生”关系。建议构建两批作业并使用invokeAll(batch1); invokeAll(batch2);invokeAll() 方法将执行所有任务并阻塞直到它们完成。您可能需要将您的Runnables 包装为Callables,您可以使用Executors.callable(Runnable r) 执行此操作。 (@Cameron Skinner 击败我获得了一些代码示例,请参阅该答案以获取更多信息......)

执行器的全部意义在于抽象出执行的细节,因此除非明确说明,否则不能保证顺序。如果您想要严格的顺序执行,请在您正在运行的线程中执行(最简单),在单线程执行程序中执行,ala Executors.newSingleThreadExecutor(),或显式同步任务。如果你想做后者,你可以使用屏障或闩锁,并将相关任务阻塞在屏障/闩锁上。您还可以让第一个任务块实现 Callable,返回 Future,并让相关任务调用 myFuture.get(),这将导致它们阻塞,直到返回结果。

如果您详细说明您的具体应用,我们或许可以提供更具体的帮助。

【讨论】:

  • 感谢您提供详细信息!!!您能否详细说明屏障的用法?我不确定我是否明白了那部分
  • @user384706:嗯,对于这个任务来说,障碍可能有点过头了,但从概念上讲,如果你有一批任务代表一个工作单元需要一起完成,然后另一批才能再次启动,你可以使用download.oracle.com/javase/6/docs/api/java/util/concurrent/… 来实现这一点。在你的情况下它是重量级的——当你有很多迭代时更常用,而且你只有 batch1 -> batch2
【解决方案2】:

这是正确的行为。您无法保证 Runnable 的执行顺序。

执行程序并行运行,而您似乎希望任务串行运行。您可以提交前 50 个作业,等待它们完成,然后提交后 50 个作业,或者(如果执行顺序很重要)在单个线程中运行它们。

例如,

for (Future<Whatever> f: service.invokeAll(first50tasks)) {
    addResultToList(f.get());
}
Future<Whatever> output = service.invokeAll(second50tasks);

【讨论】:

  • invokeAll(tasks) 与依次提交每个 callable 有什么区别?做invokeAll是否更优化?
  • invokeAll 仅在所有任务完成后返回,因此您无需编写代码等待。
【解决方案3】:

也许您可以 execute 前 50 个、shutdownawaitTermination,然后才 execute 其他 50 个?示例代码见this answer

【讨论】:

  • 我不确定如何使用 awaitTermination;。 Javadoc 说:在关闭请求后阻塞,直到所有任务都完成执行,或者发生超时,或者当前线程被中断,以先发生者为准我不想关闭执行程序并且不确定我是否想超时
  • 没有理由为了确保工作完成而放弃一个完美的执行器...invokeAll() 这样做,或者您可以收集Futures 并等待它们完成。
  • @user384706:我的回答链接了有关如何使用awaitTermination 的代码示例。然而,andersoj 的回答听起来是正确的做法。
猜你喜欢
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 2011-06-15
  • 2015-02-15
  • 1970-01-01
  • 2012-02-27
  • 2012-05-06
  • 1970-01-01
相关资源
最近更新 更多