2

我正在开发一个具有不同运行时间的任务的多线程应用程序。当一个线程完成时,有没有办法让它从仍在运行的线程中接管一些任务?

这是一个例子。我用 5 个线程启动我的程序,每个线程有 50 个任务。当最快运行的线程完成时,另一个线程仍有 40 个任务要完成。如何让已完成的线程从另一个线程中获取 20 个任务,因此每个线程继续处理 20 个,而不是等待正在运行的线程完成剩余的 40 个?

4

4 回答 4

4

最好使用ThreadPoolExecutor. 它会自动将任务分配给空闲线程。

于 2016-01-05T14:30:37.530 回答
3

使用由Executors类创建的线程池:

 ExecutorService es = Executors.newFixedThreadPool(5);
 List<Runnable> tasks = // create your 50 runnable
 List<Future<?>> futures = new ArrayList<>(tasks.size());
 for(Runnable r : tasks) {
     Future<?> f = es.submit(t);
     futures.add(f);
 }

该文档很好地解释了它的工作原理,因此我建议您看一下。

于 2016-01-05T14:35:09.327 回答
3

使用ForkJoinPool

ForkJoinPool 与其他类型的 ExecutorService 的不同之处主要在于采用了工作窃取:池中的所有线程都尝试查找并执行由其他活动任务创建的子任务(如果不存在,则最终阻塞等待工作)。当大多数任务产生其他子任务(大多数 ForkJoinTasks 也是如此)时,这可以实现高效处理。在构造函数中将 asyncMode 设置为 true 时,ForkJoinPools 也可能适用于从未加入的事件样式任务。

Java 8 在 Executors 中提供了另外一种 API

static ExecutorService  newWorkStealingPool()

创建一个工作窃取线程池,使用所有可用处理器作为其目标并行度级别。

ForkJoinPool 任务窃取

有关更多详细信息,请查看这篇igvtia 文章Ilya Grigorik

看看其他相关的 java 并发 API @教程ThreadPoolExecutorExecutorService

于 2016-01-05T14:38:33.613 回答
0

不要让线程承担多个任务。这样,任何完成其任务的线程都会接受队列中的下一个可用任务。这些线程不是为每个任务创建新的,而是被重复使用,因此开销很小。

考虑 - 2 个线程每个有 20 个任务,如果第二个线程尚未完成,您希望第二个线程接管第一个线程的任务。与此相比,队列中有 40 个任务由 2 个线程提供服务,这意味着任务总是会尽快执行,而无需尝试在线程之间移动它们的复杂性。

我没有看到问题中的逻辑 - 如果您的任务组由于排序问题而不能多线程(这是我可以看到将本身是一组任务的任务提交到队列中的唯一原因),那么你不能让另一个线程接管未完成的处理(因为这样整个组的顺序就会被破坏)。如果不需要顺序处理,那就把所有的任务都扔到队列中,让它们尽快执行。

如果您总是希望给定组中的任务更快执行,请为它们分配更高的优先级并使用由多个线程提供服务的优先级队列。

于 2016-12-29T23:02:36.247 回答