java ThreadPool 不按顺序运行任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4470492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 06:32:54  来源:igfitidea点击:

ThreadPool does not run tasks in sequence

javamultithreadingexecutorserviceexecutor

提问by Cratylus

I am using the Executorframework specifically Executors.newCachedThreadPool();
I have a list of Runnables e.g. 100.
The first 50, each create a value (stored in a list) to be used by the last 50.
I thought that if I pass the Runnables in the executor.execute()in the order they are in the list, they would be also executed in the same order.
But this is not happening.
The tasks seem to be executed in random order and they are interleaved, not executed in sequence.
Is this how it is suppose to work? Any way to work around this problem?

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

Thanks

谢谢

回答by andersoj

You need to submit the jobs in two batches, or otherwise create an explicit "happens-before" relationship. Suggest building two batches of jobs and using invokeAll(batch1); invokeAll(batch2);The invokeAll()method will execute all of the tasks and block until they complete. You may need to wrap your Runnables as Callables, which you can do with Executors.callable(Runnable r). (@Cameron Skinner beat me to getting some code example, see that answer for more...)

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

The whole point of executors is to abstract away the specifics of execution, so ordering is not guaranteed unless explicitly stated. If you want strictly sequential execution, do it in the thread you're running in (simplest), do it in a single-threaded executor, ala Executors.newSingleThreadExecutor(), or explicitly synchronize the tasks. If you want to do the latter, you could use a barrier or latch and have the dependent tasks block on the barrier/latch. You could also have the first block of tasks implement Callable, return Future, and have the dependent tasks call myFuture.get()which would cause them to block until the results are returned.

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

If you say more about your specific application, we might be able to help more specifically.

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

回答by Cameron Skinner

That is the correct behaviour. You have no guarantees about which order the Runnables are executed.

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

Executors run in parallel, whereas it seems that you want the tasks run in serial. You can either submit the first 50 jobs, wait for them to finish, then submit the second 50 jobs, or (if the order of execution is important) just run them all in a single thread.

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

For example,

例如,

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

回答by Fabian Steeg

Perhaps you could executethe first 50, shutdownand awaitTermination, and only then executethe other 50? See this answerfor some sample code.

也许你可以execute第50,shutdownawaitTermination,然后才是execute其他50?有关一些示例代码,请参阅此答案