提问者:小点点

完全可实现可靠性的未来递归


这是CompletableFuture非常基本的递归,我想让系统可靠,所以每次有异常再次重启进程,我相信它有太多的问题,希望得到你的反馈

private CompletableFuture<?> recursion() {
return CompletableFuture.runAsync(() -> {
    //code here
    }).handleAsync((v, th) -> {
        if (th != null)
            return this.recursion();
        else
            return v;
    });
}

编辑1:

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

AtomicInteger tries =5;
private void recursion() {
    CompletableFuture.runAsync(() -> {
    //code here
    }).whenCompleteAsync((v, th) -> {
        if (th != null && ( tries.getAndDecrement() > 0 ) ){
            Thread.sleep(1000);
            this.recursion();
        });
}

请给我你的反馈,我在争论,但真的很感激。


共1个答案

匿名用户

一般来说,当异常发生时,简单地重试操作,而不处理异常来分析失败的原因,离创建可靠的系统还很远。

然而,如果您想实现重试,您的代码将无法正确执行此操作。

您的代码恰好被编译器接受,因为您使用的操作不产生值并返回CompletableFuture

传递给handleAsync的双函数应该提供结果值,但您调用的this. postsion()会产生CompletableFuture

如果您将返回类型声明为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;
        }
    });
}

很容易适应使用RunnablerunAsyncCompletableFuture

更新:如果您只想安排重试而不向发起者提供反馈,您可以通过等待延迟过去来实现它而不阻塞线程:

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);
                }
            }
        });
}