简体   繁体   English

从列表中同时获取所有期货

[英]Get all the Futures at the same time from a list

I have an arraylist of Futures that are executed by an ExecutorService:我有一个由 ExecutorService 执行的 Futures 数组列表:

ExecutorService executor = Executors.netFixedThreadPoolExecytor(COUNT);
for(myObj : list){
    Future<myObj> future = executor.submit()(() - > some.method(myObj));
    futurelist.add(future);
}
executor.shutdown()

I want to be able to call the get() function for all the Futures in the array at the same time so the Thread won't wait for completion until it takes the next element.我希望能够同时为数组中的所有 Future 调用 get() 函数,以便线程不会等待完成,直到它需要下一个元素。 The closer I have come is to take all the elements from the array and loop trough them:我越来越接近是从数组中取出所有元素并循环遍历它们:

for(Future f : futurelist) {
    f.get()
}

How can I make that all the futures to be executed and completed at the same time ?我怎样才能让所有期货同时执行和完成?

Await termination of your executor service等待您的执行人服务终止

Your comments indicate that your real goal is to wait until all your submitted tasks have been completed (or cancelled).您的评论表明您的真正目标是等到所有提交的任务都完成(或取消)。

You said:你说:

I want somehow to call get() after all the Futures are completed我想在所有期货完成后以某种方式调用 get()

A Future does not get completed. Future没有完成。 A Future represents: Future代表:

  • The status of a Callable / Runnable that may have yet to start execution, may be currently executing, or may have ended its execution.可能尚未开始执行、可能正在执行或可能已结束执行的Callable / Runnable的状态。
  • The result of a Callable object's work, returned by its call method . The result payload on the Callable对象的工作结果,由其call方法返回. The result payload on the . The result payload on the Future` is empty until the task has completed and returned an object. Future` . The result payload on the是空的,直到任务完成并返回一个对象。

To wait until all the submitted tasks are done, you simply need to call shutdown and awaitTermination on your executor service.要等到所有提交的任务完成,您只需在您的执行程序服务上调用shutdownawaitTermination

And by the way, you can submit a collection of Callable objects to your executor service, if that suits your situation.顺便说一句,如果适合您的情况,您可以将Callable对象的集合提交给您的执行程序服务。 You will get back a collection of Future objects.您将返回一组Future对象。 Getting those Future objects does not mean the tasks are done, it means the tasks were successfully submitted to an executor service.得到这些Future对象并不意味着任务都做了,就意味着任务已成功提交到执行服务。 By the time you get a Future back, the task may or may not have started execution.当你得到一个Future ,任务可能已经开始执行,也可能没有开始执行。

Here is some example code.这是一些示例代码。

Set up a collection of Callable objects.设置Callable对象的集合。 Our example here returns a UUID .我们这里的示例返回一个UUID

int countTasks = 10;
List < Callable < UUID > > tasks = new ArrayList <>( countTasks );
for ( int i = 0 ; i < countTasks ; i++ )
{
    Callable < UUID > c = ( ) -> { return UUID.randomUUID(); };
    tasks.add( c );
}

Set up an executor service to perform our tasks on background threads.设置执行程序服务以在后台线程上执行我们的任务。 Establish a List to be filled with Future objects representing each of our task's work.建立一个List以填充代表我们每个任务工作的Future对象。

ExecutorService executorService = Executors.newCachedThreadPool();
List < Future < UUID > > futures = null;

Ask our executor service to perform those tasks.要求我们的执行程序服务来执行这些任务。 The service collects the instantiated Future objects, returning to us the collection.该服务收集实例化的Future对象,将集合返回给我们。

try { futures = executorService.invokeAll( tasks ); } catch ( InterruptedException e ) { e.printStackTrace(); }

We immediately ask the executor service to go into shutdown mode.我们立即要求执行程序服务进入关闭模式。 This stops further tasks from being submitted, but allows already-submitted tasks to continue.这会阻止提交更多任务,但允许已提交的任务继续。 We then tell the executor service to wait a certain amount of time for all submitted tasks to complete.然后我们告诉 executor 服务等待一定的时间让所有提交的任务完成。 We check to see if the termination completed or timed-out.我们检查终止是否完成或超时。

executorService.shutdown();
try
{
    boolean terminationComleted = executorService.awaitTermination( 1 , TimeUnit.MINUTES );
    if ( ! terminationComleted ) System.out.println( "ERROR - Submitted tasks not completed before time-out. " + Instant.now() );
}
catch ( InterruptedException e ) { e.printStackTrace(); }

The call to awaitTermination blocks until either all tasks are done or the time-out is reached.awaitTermination的调用会阻塞,直到所有任务都完成或达到超时为止。 So beyond that call means the executor service is shutdown.因此,超出该调用意味着执行程序服务已关闭。 So we can now examine our collection of Future objects to see the fruits of our threaded work.所以我们现在可以检查我们的Future对象集合,看看我们线程工作的成果。

// At this point all submitted tasks are done, and the executor service has ended.
for ( Future < UUID > future : futures )
{
    if ( future.isCancelled() )
    {
        System.out.println( "Oops, task was cancelled. " );
    } else
    {
        try { System.out.println( "future = " + future + "  |  " + future.get() ); } catch ( InterruptedException e ) { e.printStackTrace(); }catch ( ExecutionException e ) { e.printStackTrace(); }
    }
}

Same example, in a complete class, ready to run.同样的例子,在一个完整的类中,准备运行。

package work.basil.demo.threads;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.*;

public class App4
{
    public static void main ( String[] args )
    {
        App4 app = new App4();
        app.demo();
    }

    private void demo ( )
    {
        System.out.println( "INFO - Starting method `demo`. " + Instant.now() );

        int countTasks = 10;
        List < Callable < UUID > > tasks = new ArrayList <>( countTasks );
        for ( int i = 0 ; i < countTasks ; i++ )
        {
            Callable < UUID > c = ( ) -> { return UUID.randomUUID(); };
            tasks.add( c );
        }

        ExecutorService executorService = Executors.newCachedThreadPool();
        List < Future < UUID > > futures = null;
        try { futures = executorService.invokeAll( tasks ); } catch ( InterruptedException e ) { e.printStackTrace(); }

        executorService.shutdown();
        try
        {
            boolean terminationComleted = executorService.awaitTermination( 1 , TimeUnit.MINUTES );
            if ( ! terminationComleted ) System.out.println( "ERROR - Submitted tasks not completed before time-out. " + Instant.now() );
        }
        catch ( InterruptedException e ) { e.printStackTrace(); }
        // At this point all submitted tasks are done, and the executor service has ended.
        for ( Future < UUID > future : futures )
        {
            if ( future.isCancelled() )
            {
                System.out.println( "Oops, task was cancelled. " );
            } else
            {
                try { System.out.println( "future = " + future + "  |  " + future.get() ); } catch ( InterruptedException e ) { e.printStackTrace(); }catch ( ExecutionException e ) { e.printStackTrace(); }
            }
        }

        System.out.println( "INFO - Starting method `demo`. " + Instant.now() );
    }
}

You asked:你问:

How can I make that all the futures to be executed and completed at the same time ?我怎样才能让所有期货同时执行和完成?

You cannot.你不能。

The first rule of threaded work is that you do not control the threads .线程化工作的第一条规则是,控制线程 When a thread is scheduled for execution on a core, and for how long that execution runs before suspension, all depends on the JVM , the host OS , and the momentary runtime conditions.当一个线程被安排在一个核心上执行时,以及该执行在暂停之前运行多长时间,都取决于JVM 、主机操作系统和瞬时运行时条件。

Any of your threads may be started at any time, suspended at any time, and completed at any time.您的任何线程都可以随时启动、随时暂停和随时完成。 The threads may complete in any order at any time.线程可以在任何时间以任何顺序完成。

You said:你说:

I want to be able to call the get() function for all the Futures我希望能够为所有期货调用 get() 函数

You can get all the Future objects as a collection, as shown in the code above.您可以将所有Future对象作为集合获取,如上面的代码所示。 But each Future represents the task to be executed, not the fact that it has been executed.但是每个Future代表要执行的任务,而不是它已经执行的事实。 Hence the name Future .因此名称Future

You can ask each Future object if its task is done or not by calling Future#isDone .您可以通过调用Future#isDone来询问每个Future对象的任务是否完成。 If the task has not yet begun execution, you get false .如果任务还没有开始执行,你会得到false If the task is underway (either actively executing on a core or suspended), you get false .如果任务正在进行中(在核心上主动执行或暂停),您会得到false If the task has completed its work, been cancelled, or failed from a thrown exception, then you get true .如果任务已完成其工作、被取消或因抛出异常而失败,那么您会得到true

As far as I know this is not possible to do directly with Future .据我所知,这是不可能直接用Future做的。 I would change your tasks to put their result in a queue, and then just read from the queue.我会更改您的任务以将它们的结果放入队列中,然后从队列中读取。

Maybe something like:也许是这样的:

List<Object> results = new concurrent list...
Callable<Object> task = new MyTask( results ) // inject list to hold results
List<Callable> taskList = new list...
taskList.add( taskList );
ExecutorService executor = Executors.netFixedThreadPoolExecytor(COUNT);
for(myObj : list){
    Future<myObj> future = executor.submit()(() - > some.method(myObj));
    futurelist.add(future);
}
executor.shutdown();
for( int i = 0; i < COUNT; i++ ) {
   Object result = results.poll();
   // process result...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM