如何在Java中为CompletableFuture执行资源清理?

时间:2018-10-12 08:39:51

标签: java multithreading java-threads completable-future

我在CompletableFuture中有一段代码,如果有异常,则执行重试,否则将完成任务。我已将资源传递给SupplierConsumer以执行任务,并希望在所有任务完成后重试(3次重试后success/exception)关闭这些资源。

这是一段代码:

Supplier mySupplier = new MySupplier(localContext);
CompletableFuture<String> future = CompletableFuture.supplyAsync(mySupplier);
for(int j = 0; j < (retryCount - 1); j++) {
    LOGGER.debug("MySupplier accept() Retry count: "+j);
    future = future.handleAsync((value, throwable) -> throwable == null? CompletableFuture.completedFuture(value): CompletableFuture.supplyAsync(mySupplier)).thenComposeAsync(Function.identity());
}

我打算将其放置在供应商的final块中,但是如果发生第一个异常,则该资源将被关闭,在接下来的两次重试中我将需要它们。

1)如何使其工作?

2)还有只有在例外情况下才打印重试次数的方法吗?

2 个答案:

答案 0 :(得分:0)

由于您似乎并不关心中间结果,所以最简单的解决方案是将Supplier包装在另一个处理重试的方法中:

class SupplierRetrier<T> implements Supplier<T> {
    private static final Logger LOGGER = LoggerFactory.getLogger(SupplierRetrier.class);
    final Supplier<T> wrappee;
    final int maxRetries;

    SupplierRetrier(Supplier<T> wrappee, int maxRetries) {
        Objects.requireNonNull(wrappee);
        if (maxRetries <= 0) {
            throw new IllegalArgumentException("maxRetries must be more than 0: " + maxRetries);
        }
        this.wrappee = wrappee;
        this.maxRetries = maxRetries;
    }

    @Override
    public T get() {
        RuntimeException lastException = null;
        for (int i = 0; i < maxRetries; i++) {
            try {
                LOGGER.info("MySupplier accept() Retry count: "+i);
                return wrappee.get();
            } catch (RuntimeException e) {
                lastException = e;
            }
        }
        throw lastException;
    }
}

然后,您可以将其简单地用于:

CompletableFuture<String> future = CompletableFuture.supplyAsync(
        new SupplierRetrier<>(mySupplier, retryCount));

为了清理您的上下文,只需在产生的未来上添加一个whenComplete()调用即可。无论将来如何,都将执行此操作。

future.whenComplete((r, e) -> {
    try {
        localContext.close();
    } catch (Exception e2) {
        throw new RuntimeException("Failed to close context", e2);
    }
});

答案 1 :(得分:0)

1)对于资源清理,请使用whenCompletewhenCompleteAsync

2)对于重试计数,请使用长度为int[]1的{​​{1}}。 (无论是否抛出AtomicInteger,此值均可用)

Exception