如何保持一个固定大小的ListenableFutures池?

时间:2014-08-13 19:55:00

标签: java concurrency guava future

我正在阅读Urls的大文件,并向服务请求。该请求由返回ListenableFuture的客户端执行。现在我想保留一个ListenableFuture s池,例如N期货最多同时执行。

我看到的问题是,由于第三方库,我无法控制ExecutorService ListenableFuture被执行。否则,我只需创建一个FixedSizePool并创建我自己的Callable

1)一个天真的实现是生成N期货,然后使用AllAsList,它将满足固定大小的标准,但让所有人等待最慢的请求。 乱序处理没问题。

2)稍微更好的天真选择是使用第一个想法并将其与速率限制器结合使用,方法是设置Nrate,使得并发请求数量达到良好状态近似于所需的池大小。但我实际上并没有找到一种方法来限制呼叫,例如使用RateLimiter

3)最后一个选项是生成N期货,并有一个产生新的回调。这满足了固定大小的标准,并最大限度地减少了空闲时间,但我不知道如果我的程序,即关闭文件,如何检测结束。

4)非ListenableFuture相关的方法是直接.get()结果,并通过创建一个简单的Threadpool来处理难以置信的并行任务。

为了知道作业队列是空的,即关闭文件,我正在考虑使用CountdownLatch。哪个适用于多种选择。

3 个答案:

答案 0 :(得分:1)

嗯。您如何使用java.util.concurrent.Semaphore

Semaphore gate = new Semaphore(10);
Runnable release = gate::release; // java 8 syntax.
Iterator<URL> work = ...;
while(work.hasNext() && gate.acquire()) {
  ListenableFuture f = ThirdPartyLibrary.doWork(work.next());
  f.addListener( release, MoreExecutors.sameThreadExecutor() );
}

您可以使用Futures.addCallback(ListenableFuture, FutureCallback)添加其他侦听器,以便对结果执行某些操作,只要您在成功和错误上都小心release()

它可能有用。

答案 1 :(得分:0)

你的选择3听起来很合理。如果要干净地检测所有请求何时完成,一种简单的方法是创建一个新的SettableFuture来表示完成。

当您的回调尝试从队列中获取下一个请求并发现它为空时,您可以在将来调用set()以通知任何等待所有请求完成的内容。传播个别请求期货的例外情况留给读者练习。

答案 2 :(得分:0)

使用FixedSizePool进行尴尬的并行任务,并.get()立即使用未来的结果。

这简化了代码,并允许每个工作人员具有可修改的上下文。