这是CompletableFuture
的非常基本的递归,我想建立可靠的系统,所以每次重新启动过程都有异常,我相信它有太多问题,想要得到你的反馈意见
private CompletableFuture<?> recursion() {
return CompletableFuture.runAsync(() -> {
//code here
}).handleAsync((v, th) -> {
if (th != null)
return this.recursion();
else
return v;
});
}
Edit1:
int tries =5;
private CompletableFuture<?> recursion() {
return CompletableFuture.runAsync(() -> {
//code here
}).handleAsync((v, th) -> {
if (th != null && tries-- > 0){
Thread.sleep(1000);
return this.recursion();
}else
return v;
});
}
EDIT2:
清除代码,因为返回CompletableFuture<?>
没有必要,因此考虑@Holger评论并使用AtomicInteger进行尝试,将其挂起void
AtomicInteger tries =5;
private void recursion() {
CompletableFuture.runAsync(() -> {
//code here
}).whenCompleteAsync((v, th) -> {
if (th != null && ( tries.getAndDecrement() > 0 ) ){
Thread.sleep(1000);
this.recursion();
});
}
请将反馈发给我,我正在争论,但我真的很感激。
答案 0 :(得分:0)
通常,只是在发生异常时重试操作,而不处理异常以分析失败的原因,远远没有创建可靠的系统。
然而,如果要实现重试,则代码无法正确执行此操作。
您的代码恰好被编译器接受,因为您使用的操作不会生成值并返回CompletableFuture<?>
。这隐藏了代码的问题:
传递给handleAsync
的双功能应该提供结果值,但是你调用this.recursion()
产生CompletableFuture<?>
。编译器并不介意在非例外情况下返回v
,因为Void
和CompletableFuture<?>
有一个共同的超类型Object
,所以整个方法是有效地返回与返回类型CompletableFuture<Object>
兼容的CompletableFuture<?>
。
如果您将返回类型声明为CompletableFuture<Void>
,则会立即识别出逻辑错误:在例外情况下,您将启动另一个异步操作,但由于您没有检查它的结果,只是返回CompletableFuture<?>
,然后将其视为Object
,调用者将永远不会注意到重试(或后续重试)是否失败。来电者将始终收到报告成功的CompletableFuture<?>
,其中包含(Void)null
或CompletableFuture<?>
作为结果值。
通常,您不应该使用递归进行重复。没有理由这样做。让我们用一个返回值的动作演示逻辑:
CompletableFuture<String> performAsyncAction() {
Supplier<String> action=() -> {
if(Math.random()>0.2)
throw new IllegalStateException("simulated failure");
return "value implying success";
};
int retries=5;
return CompletableFuture.supplyAsync(() -> {
try { return action.get(); }
catch(Throwable t) {
for(int i=0; i<retries; i++) try {
Thread.sleep(1000);
return action.get();
} catch(Throwable next) { t.addSuppressed(next); }
throw t;
}
});
}
很容易适应使用Runnable
,runAsync
和CompletableFuture<Void>
。
更新:如果您只是想在不向发起人提供反馈的情况下安排重试,您可以通过等待延迟过去来实现它而不会阻塞线程:
static ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
static void performAsyncAction(Runnable r, int tries, long delay, TimeUnit u) {
if(tries>0)
e.execute(()-> { try { r.run(); } catch(Throwable t) {
e.schedule(()->performAsyncAction(r, tries-1, delay, u), delay, u);
}});
}
这使用递归,因为它解决了lambda表达式。如果你使用内部类,那么在没有递归的情况下也可以这样做:
static ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
static void performAsyncAction(Runnable r, int tries, long delay, TimeUnit u) {
if(tries>0)
e.execute(new Runnable() {
int left = tries;
public void run() {
try { r.run(); } catch(Throwable t) {
if(--left > 0) e.schedule(this, delay, u);
}
}
});
}