我有以下代码,该代码在远程服务器上安排任务,然后使用轮询完成ScheduledExecutorService#scheduleAtFixedRate
。任务完成后,它将下载结果。我想将a返回Future
给调用方,以便他们可以确定阻止时间和阻止时间,并为他们提供取消任务的选项。
我的问题是,如果客户端取消Future
该download
方法返回的值,则whenComplete
块不会执行。如果我删除thenApply
它。很明显,我对Future
构图有些误解…我应该改变什么?
public Future<Object> download(Something something) {
String jobId = schedule(something);
CompletableFuture<String> job = pollForCompletion(jobId);
return job.thenApply(this::downloadResult);
}
private CompletableFuture<String> pollForCompletion(String jobId) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
CompletableFuture<String> completionFuture = new CompletableFuture<>();
ScheduledFuture<?> checkFuture = executor.scheduleAtFixedRate(() -> {
if (pollRemoteServer(jobId).equals("COMPLETE")) {
completionFuture.complete(jobId);
}
}, 0, 10, TimeUnit.SECONDS);
completionFuture
.whenComplete((result, thrown) -> {
System.out.println("XXXXXXXXXXX"); //Never happens unless thenApply is removed
checkFuture.cancel(true);
executor.shutdown();
});
return completionFuture;
}
同样,如果我这样做:
return completionFuture.whenComplete(...)
代替
completionFuture.whenComplete(...);
return completionFuture;
whenComplete
也永远不会执行。这对我来说似乎很违反直觉。从逻辑上说,Future
返回应该不是whenComplete
我应该坚持的那个吗?
编辑:
我更改了代码以明确向后传播取消。这是令人讨厌和难以理解的,但是它可以正常工作,我找不到更好的方法:
public Future<Object> download(Something something) throws ChartDataGenException, Exception {
String jobId = schedule(something);
CompletableFuture<String> job = pollForCompletion(jobId);
CompletableFuture<Object> resulting = job.thenApply(this::download);
resulting.whenComplete((result, thrown) -> {
if (resulting.isCancelled()) { //the check is not necessary, but communicates the intent better
job.cancel(true);
}
});
return resulting;
}
编辑2:
我发现了tascalate-concurrent,这是一个出色的库,提供sane的明智实现CompletionStage
,并支持可以通过DependentPromise
透明方式反向传播取消的相关承诺(通过类)。似乎非常适合此用例。
这应该足够了:
DependentPromise
.from(pollForCompletion(jobId))
.thenApply(this::download, true); //true means the cancellation should back-propagate
请注意,没有测试这种方法。
您的结构如下:
┌──────────────────┐
│ completionFuture |
└──────────────────┘
↓ ↓
┌──────────────┐ ┌───────────┐
│ whenComplete | │ thenApply |
└──────────────┘ └───────────┘
因此,当您取消thenApply
未来时,原始completionFuture
对象不会受到影响,因为它与thenApply
舞台无关。但是,如果您不链接该thenApply
阶段,那么您将返回原始completionFuture
实例,并且取消该阶段会导致所有相关阶段的取消,从而使whenComplete
操作立即执行。
schedule(something)和
pollRemoteServer(jobId)`。如果您的应用程序状态以某种方式更改,使得取消下载后再也无法满足此条件,那么这种未来将永远无法完成…
关于您的最后一个问题,哪个期货是“我应该坚持的那个期货?”,实际上,并不需要线性的期货链,而方便的方法CompletableFuture
可以轻松地创建这样的链,而不仅仅是通常,这是最没有用的事情,因为如果您具有线性依赖性,则只需编写一段代码即可。您将两个独立阶段链接在一起的模型是正确的,但是取消不能通过它起作用,但是它也不可以通过线性链来起作用。
如果希望能够取消源阶段,则需要对其进行引用,但是,如果想要获得从属阶段的结果,则也需要对该阶段进行引用。
问题内容: 我无法理解)和之间的区别。 那么,有人可以提供有效的用例吗? 从Java文档中: 返回一个新值,当此阶段正常完成时,将使用该阶段的结果作为所提供函数的参数来执行该操作。 返回一个新值,当此阶段正常完成时,将以该阶段作为所提供函数的参数来执行此操作。 我得到扩展的CompletionStage 的第二个参数,而没有扩展。 有人可以提供一个例子,说明我必须在什么情况下使用以及何时使用? 问
我搞不清)和之间的区别。 那么,有人能提供一个有效的用例吗? 从Java文档中: 返回一个新的,当此阶段正常完成时,将以此阶段的结果作为所提供函数的参数执行该。 返回一个新的,当此阶段正常完成时,将以此阶段作为所提供函数的参数执行该。 我发现的第二个参数扩展了CompletionStage,而没有扩展CompletionStage。 谁能提供一个例子,在什么情况下我必须使用以及什么时候使用?
我正在使用Jersey 2.5.1和Jackson 2.2。用于构建JSON Rest web服务。我也用2个ExceptionMappers启动并运行了它,但对于“非json”请求,应用程序不会抛出任何异常! > 如果抛出NullPointerException,将调用ExceptionMapper 如果JSon映射有问题,将调用ExceptionMapper 我的问题:1.请求正文:{}工作2
我确信这是一个非常简单的东西,但由于我是一个Python/tKinter n00b,它打败了我,我已经完成了谷歌搜索。感激地得到的任何帮助:)
假设我有一种情况,我 ;调用两个存储库来获取项目。 当这两个都完成并反馈结果时,我怎样才能得到反馈呢?传统上,我会一个一个地调用这两个,然后再做剩下的逻辑。在这里,我想加快这个过程。 I ;试图做thenCombine()这样的事情,但两者都是不同的对象,我无法在这个lambda中写入逻辑。有谁能提出更好的方法吗?
问题内容: 假设我有以下代码: 案件: 这里输出将2.现在的情况: 我在这个博客中读到,每个步骤都是在单独的线程中执行的,并且“同时”执行(这意味着在先于结束之前先开始执行),如果是这样,那么如果第一步没有完成,那么第二步的输入参数值是多少? 如果第二步不采取措施,第一步的结果将流向何方?第三步将采取哪一步的结果? 如果第二步必须等待第一步的结果,那么意义何在? 这里x-> x + 1只是为了说明