Java:如何从运行的线程中获取完成的线程来拾取任务

时间:2016-01-05 14:25:46

标签: java multithreading executorservice threadpoolexecutor forkjoinpool

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

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

4 个答案:

答案 0 :(得分:4)

使用ThreadPoolExecutor会更好。它会自动将任务分配给免费线程。

答案 1 :(得分: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);
 }

文档很好地解释了它是如何工作的所以我建议你看一下。

答案 2 :(得分:3)

使用ForkJoinPool

  

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

Java 8在Executors中提供了一个API

static ExecutorService  newWorkStealingPool()
  

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

ForkJoinPool task stealing

有关详细信息,请Ilya Grigorik查看此igvtia article

查看其他相关的Java并发API @ tutorials,例如ThreadPoolExecutorExecutorService等。

答案 3 :(得分:0)

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

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

我没有看到问题中的逻辑 - 如果由于排序问题而导致无法进行多线程的任务组(这是我可以看到提交本身就是一个组的任务的唯一原因任务进入队列),然后你不能让另一个线程接管未完成的处理(因为那时整个组的排序将被打破)。如果您不需要顺序处理,则将所有任务抛出到队列中并让它们尽快执行。

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