如何使用ExecutorService管理未知数量的Callables的返回值?

时间:2013-10-23 11:56:07

标签: java multithreading executorservice callable

我想创建一个具有固定线程池大小的singleton-ExecutorService。另一个线程将使用Callables提供ExecutorService,并且我想在执行完成后立即解析Callables的结果(最佳)。

我真的不确定如何正确实现这一点。 我最初的想法是singleton-ES中的一个方法,它通过“submit(callable)”将一个Callable添加到ExecutorService,并将生成的Future存储在单例内的HashMap或ArrayList中。另一个线程会在给定的时间间隔内检查Futures的结果。

但不知怎的,这个解决方案并没有“感觉正确”,而且我没有在其他地方找到这个用例的解决方案,所以在我编写我后悔的东西之前,我问你们。 你会如何处理这个问题?

我期待您的回复!

4 个答案:

答案 0 :(得分:1)

您可以使用MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUMBER));创建服务 并使用guava ListenableFuture来解析结果,你也可以将自行车用于侦听未来的结果。

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
  public Explosion call() {
    return pushBigRedButton();
  }
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
  // we want this handler to run immediately after we push the big red button!
  public void onSuccess(Explosion explosion) {
    walkAwayFrom(explosion);
  }
  public void onFailure(Throwable thrown) {
    battleArchNemesis(); // escaped the explosion!
  }
});

答案 1 :(得分:1)

import java.util.concurrent.*;

public class PostProcExecutor extends ThreadPoolExecutor {

  // adjust the constructor to your desired threading policy
  public PostProcExecutor(int corePoolSize, int maximumPoolSize,
      long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
  }

  @Override
  protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable) {
      @Override
      protected void done()
      {
        if(!isCancelled()) try {
          processResult(get());
        } catch(InterruptedException ex) {
          throw new AssertionError("on complete task", ex);
        } catch(ExecutionException ex) {
          // no result available
        }
      }
    };
  }

  protected void processResult(Object o)
  {
    System.out.println("Result "+o);// do your post-processing here
  }
}

答案 2 :(得分:1)

使用ExecutorCompletionService。这样,您可以在Callable(s)准备就绪后立即获得结果。完成服务的take方法阻止等待每个任务完成。

以下是来自java doc的示例:

void solve(Executor e,
            Collection<Callable<Result>> solvers)
     throws InterruptedException, ExecutionException {
     CompletionService<Result> ecs
         = new ExecutorCompletionService<Result>(e);
     for (Callable<Result> s : solvers)
         ecs.submit(s);
     int n = solvers.size();
     for (int i = 0; i < n; ++i) {
         Result r = ecs.take().get();
         if (r != null)
             use(r);
     }
 }

答案 3 :(得分:1)

您可以使用 ExecutorCompletionService 来实现它。

以下步骤可以帮助您。

  1. 使用 Runtime.getRuntime()。availableProcessors()填充可用处理器的数量。让我们将值保存在变量availableProcessors中。

  2. 初始化ExecutorService,例如 service = Executors.newFixedThreadPool(availableProcessors)

  3. 初始化ExecutorCompletionService,假设Callable的结果是整数数组整数[], ExecutorCompletionService completionService = new ExecutorCompletionService(service)

  4. 使用 completionService.submit 提交任务。

  5. 使用 completionService.take()。get()来获取任务的每个结果(可调用)。

  6. 根据以上步骤,您可以获得所有可调用的结果,并做一些您想要的业务。