如何在CompletableFuture中返回AutoCloseable对象并在whenComplete中免手动关闭?
解决CompletableFuture返回Jedis时自动关闭的问题
你的核心问题是try-with-resources会在supplyAsync的lambda执行完毕后立即关闭Jedis,导致后续whenComplete中拿到的是已关闭的实例,无法正常使用。以下是两种可行的解决方案:
方案1:延迟关闭逻辑到whenComplete阶段
不在supplyAsync内使用try-with-resources,而是直接获取Jedis实例,然后在whenComplete回调中统一处理资源关闭(无论成功或异常):
@Override public CompletableFuture<Jedis> execute() { if (!isServiceActive()) { return CompletableFuture.completedFuture(null); } return CompletableFuture.supplyAsync(() -> { try { // 直接获取资源,不提前关闭 return pool.getResource(); } catch (RuntimeException e) { logger.severe("Impossibile ottenere una nuova risorsa Jedis!", e); throw new CompletionException(e); } }, executor) // 在whenComplete中统一关闭Jedis,确保资源释放 .whenComplete((jedis, throwable) -> { if (jedis != null) { try { jedis.close(); } catch (Exception e) { logger.warning("关闭Jedis资源失败", e); } } }); }
说明
supplyAsync返回的是活跃的Jedis实例,你可以在whenComplete中正常操作该实例。- 无论后续流程是正常完成还是抛出异常,
whenComplete都会执行,保证Jedis资源被正确释放。 - 注意:调用方不能在
whenComplete之后再使用返回的Jedis实例,因为此时已经被关闭。
方案2:封装Redis操作,不直接返回Jedis实例(推荐)
如果你的业务场景是要执行Redis命令而非直接操作Jedis对象,建议直接返回命令执行结果,这样可以继续使用try-with-resources保证资源安全:
// 示例:执行GET命令并返回结果 public CompletableFuture<String> executeGet(String key) { if (!isServiceActive()) { return CompletableFuture.completedFuture(null); } return CompletableFuture.supplyAsync(() -> { try (Jedis jedis = pool.getResource()) { // 直接在try块内完成所有Redis操作 return jedis.get(key); } catch (RuntimeException e) { logger.severe("获取Jedis资源或执行命令失败", e); throw new CompletionException(e); } }, executor); }
说明
- 这种方式符合资源管理的最佳实践,调用方无需关心Jedis的创建和关闭,完全由try-with-resources自动处理。
- 避免了调用方误操作已关闭的Jedis实例的风险,同时简化了业务逻辑。
内容的提问来源于stack exchange,提问作者renvins
相关产品推荐
相关产品推荐

