【发布时间】:2017-03-08 04:26:41
【问题描述】:
我有一个场景,我必须轮询远程服务器检查任务是否已完成。完成后,我会进行不同的调用来检索结果。
我最初认为我应该使用SingleThreadScheduledExecutor 和scheduleWithFixedDelay 进行轮询:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture future = executor.scheduleWithFixedDelay(() -> poll(jobId), 0, 10, TimeUnit.SECONDS);
public void poll(String jobId) {
boolean jobDone = remoteServer.isJobDone(jobId);
if (jobDone) {
retrieveJobResult(jobId);
}
}
但由于我只能向scheduleWithFixedDelay 提供无法返回任何内容的Runnable,所以我不知道future 何时会完成,如果有的话。打电话给future.get() 是什么意思?我在等什么结果?
当我第一次检测到远程任务已经完成时,我想执行一个不同的远程调用并将其结果设置为future 的值。我想我可以为此使用 CompletableFuture,我会将其转发到我的 poll 方法,该方法又会将其转发到最终完成它的 retrieveTask 方法:
CompletableFuture<Object> result = new CompletableFuture<Object>();
ScheduledFuture future = executor.scheduleWithFixedDelay(() -> poll(jobId, result), 0, 10, TimeUnit.SECONDS);
public void poll(String jobId, CompletableFuture<Object> result) {
boolean jobDone = remoteServer.isJobDone(jobId);
if (jobDone) {
retrieveJobResult(jobId, result);
}
}
public void retrieveJobResult(String jobId, CompletableFuture<Object> result) {
Object remoteResult = remoteServer.getJobResult(jobId);
result.complete(remoteResult);
}
但这有很多问题。一方面,CompletableFuture 似乎并不适合这种用途。相反,我认为我应该做CompletableFuture.supplyAsync(() -> poll(jobId)),但是当我的CompletableFuture 被取消/完成时,我将如何正确关闭executor 并取消它返回的future?感觉轮询应该以完全不同的方式实现。
【问题讨论】:
-
您也可以提交 Callables(即返回结果):docs.oracle.com/javase/7/docs/api/java/util/concurrent/…
-
@Thilo 仅用于一次性任务,不适用于 scheduleWithFixedDelay 或 scheduleAtFixedRate,因此轮询结束
-
@Thilo 我认为
scheduleWithFixedDelay不会收到Callable。 -
Op,我认为你在做正确的事。
CompletableFuture实际上是异步编程框架中的一个承诺。然而,你应该暴露的是一个无法完成的正常未来。并且您所有后续代码都应该订阅该未来。我看不出有什么问题。什么让你困惑? -
@HuStmpHrrr 所有示例似乎都在做
supplyAsync,而不是显式创建CompletableFuture。但更重要的是,在我的情况下,我需要在未来完成时关闭执行程序。我应该继承CompletableFuture并覆盖complete、completeExceptionally和cancel来执行此操作吗?我应该担心取消我从执行人那里得到的ScheduledFuture吗?
标签: java concurrency future executorservice completable-future