我正在使用返回CompletableFuture
的API来查询设备(类似于digitalpetri modbus)。
我需要使用几个选项来调用此API来查询设备并弄清楚它是什么 - 这基本上是试验和错误,直到成功为止。这些是我无法更改的嵌入式设备协议,但您可以将该过程视为类似于以下内容:
虽然API使用期货,但实际上,通信是串行的(通过相同的物理线路),因此它们永远不会同步执行。一旦我知道它是什么,我希望能够停止尝试并让呼叫者知道它是什么。
我已经知道我只能通过any
(见下文)得到一个期货的结果,但这可能导致应该避免的额外尝试。
是否有一种链接期货的模式,一旦其中一个成功,你就会停止?
类似,但浪费了非常有限的资源。
List<CompletableFuture<String>> futures = Arrays.asList(
CompletableFuture.supplyAsync(() -> "attempt 1"),
CompletableFuture.supplyAsync(() -> "attempt 2"),
CompletableFuture.supplyAsync(() -> "attempt 3"));
CompletableFuture<String>[] futuresArray = (CompletableFuture<String>[]) futures.toArray();
CompletableFuture<Object> c = CompletableFuture.anyOf(futuresArray);
答案 0 :(得分:1)
假设您有一个如您所描述的“伪异步”方法,即它具有异步API但需要执行某些锁定:
private final static Object lock = new Object();
private static CompletableFuture<Boolean> pseudoAsyncCall(int input) {
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
System.out.println("Executing for " + input);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return input > 3;
}
});
}
要检查此方法的List<Integer>
个输入,您可以使用递归合成按顺序检查每个输入:
public static CompletableFuture<Integer> findMatch(List<Integer> inputs) {
return findMatch(inputs, 0);
}
private static CompletableFuture<Integer> findMatch(List<Integer> inputs, int startIndex) {
if (startIndex >= inputs.size()) {
// no match found -- an exception could be thrown here if preferred
return CompletableFuture.completedFuture(null);
}
return pseudoAsyncCall(inputs.get(startIndex))
.thenCompose(result -> {
if (result) {
return CompletableFuture.completedFuture(inputs.get(startIndex));
} else {
return findMatch(inputs, startIndex + 1);
}
});
}
这将使用如下:
public static void main(String[] args) {
List<Integer> inputs = Arrays.asList(0, 1, 2, 3, 4, 5);
CompletableFuture<Integer> matching = findMatch(inputs);
System.out.println("Found match: " + matching.join());
}
输出:
Executing for 0
Executing for 1
Executing for 2
Executing for 3
Executing for 4
Found match: 4
正如您所看到的,当您的API(5
)保持异步时,不会调用输入findMatch()
。
答案 1 :(得分:0)
我认为,在您检索结果后,您可以做的最好的事情是
futures.forEach(f -> f.cancel(true));
这不会影响产生结果的人,并尽力阻止其他人。既然IIUC你是从外部来源获得的,那么它并不能保证它会真正中断它们的工作。
但是,因为
这个类没有直接控制导致它完成的计算,取消被视为另一种形式的异常完成
(来自CompletableFuture
doc),我怀疑它会做你真正想要的。