如何使用ExecutorService进行轮询,直到结果到达
我有一个场景,我必须轮询远程服务器检查任务是否已完成。 一旦有,我会进行不同的调用以检索结果。
我原本认为我应该使用带有scheduleWithFixedDelay
的SingleThreadScheduledExecutor
进行轮询:
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); } }
但是因为我只能提供一个Runnable
来scheduleWithFixedDelay
不能返回任何东西的scheduleWithFixedDelay
,所以我不明白future
什么时候会完成。 调用future.get()
甚至意味着什么? 我在等什么结果?
我第一次检测到远程任务已经完成,我想执行一个不同的远程调用并将其结果设置为future
的值。 我想我可以使用CompletableFuture,我会转发到我的poll
方法,然后将它转发到我最终完成它的retrieveTask
方法:
CompletableFuture result = new CompletableFuture(); ScheduledFuture future = executor.scheduleWithFixedDelay(() -> poll(jobId, result), 0, 10, TimeUnit.SECONDS); public void poll(String jobId, CompletableFuture result) { boolean jobDone = remoteServer.isJobDone(jobId); if (jobDone) { retrieveJobResult(jobId, result); } } public void retrieveJobResult(String jobId, CompletableFuture result) { Object remoteResult = remoteServer.getJobResult(jobId); result.complete(remoteResult); }
但这有很多问题。 例如, CompletableFuture
似乎甚至不打算用于这种用途。 相反,我应该做CompletableFuture.supplyAsync(() -> poll(jobId))
我想,但是当我的CompletableFuture
取消/完成时,我将如何正确关闭executor
并取消它返回的future
? 感觉应该以一种完全不同的方式实施民意调查。
我认为CompletableFutures是一个很好的方法:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); private void run() { final Object jobResult = pollForCompletion("jobId1") .thenRun(jobId -> remoteServer.getJobResult(jobId)) .get(); } private CompletableFuture pollForCompletion(String jobId) { CompletableFuture completionFuture = new CompletableFuture<>(); final ScheduledFuture checkFuture = executor.scheduleAtFixedRate(() -> { if (remoteServer.isJobDone(jobId)) { completionFuture.complete(jobId); } }, 0, 10, TimeUnit.SECONDS); completionFuture.whenComplete((result, thrown) -> { checkFuture.cancel(true); }); return completionFuture; }
在我看来,你比其他人更担心一些风格问题。 在java 8中, CompletableFuture
有两个角色:一个是传统的未来,它为任务执行和状态查询提供了异步源; 另一个是我们通常所说的承诺。 承诺,如果您还不知道,可以被视为未来的建设者及其完成源。 所以在这种情况下,直觉上需要一个承诺,这就是你在这里使用的确切情况。 你担心的例子是介绍第一种用法的东西,而不是诺言方式。
接受这一点,你应该更容易开始处理你的实际问题。 我认为承诺应该有两个角色,一个是通知你的任务完成轮询,另一个是在完成时取消你的预定任务。 这应该是最终的解决方案:
public CompletableFuture