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

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

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

使用ForkJoinPool

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

Java 8在Executors中提供了一个API

 static ExecutorService newWorkStealingPool() 

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

ForkJoinPool任务窃取

有关详细信息,请查看Ilya Grigorik 撰写的这篇igvtia文章 。

看看其他相关的Java并发API @ 教程,如ThreadPoolExecutorExecutorService等。

最好使用ThreadPoolExecutor 。 它将自动分配任务以释放线程。

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

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

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

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

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

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

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