重试任务的两种实现:基于ScheduledFuture的方案有何优势?
重试任务第二种实现方案的优势对比
第一种:while循环简易实现
public <T> T runRetryTask(Supplier<T> supplier) { T taskExecutionResult = null; while (currentTime < expectedEndTime) { try { taskExecutionResult = supplier.get(); if (taskExecutionResult != null) return taskExecutionResult; Thread.sleep( waitTime ); } catch (Exception ex) { } } return taskExecutionResult; }
第二种:ScheduledFuture + CompletableFuture实现
public <T> CompletableFuture<T> runRetryTask(Supplier<T> supplier) { CompletableFuture<T> completableFuture = new CompletableFuture<>(); ScheduledFuture<?> scheduledFuture = executor.scheduleWithFixedDelay(() -> { T taskExecutionResult = supplier.get(); if (taskExecutionResult != null || currentTime > expectedEndTime) completableFuture.complete(taskExecutionResult); }, 0, totalTime, TimeUnit.SECONDS); completableFuture.whenComplete((result, throwable) -> { scheduledFuture.cancel(true); }); return completableFuture; }
(注:原代码返回值类型存在错误,已修正为CompletableFuture<T>,与实际逻辑匹配)
相较于第一种while循环的实现,第二种方案有以下核心优势:
- 非阻塞调用,资源利用更高效:第一种方案里
Thread.sleep()会直接阻塞当前调用线程,线程在等待期间无法处理其他任务;第二种通过线程池调度重试逻辑,调用线程可以立即返回CompletableFuture,后续异步处理结果,不会浪费线程资源。 - 线程池统一管理,适配高并发场景:第二种依赖
ScheduledExecutorService管理重试任务,能控制线程数量、复用线程,避免第一种中每个重试任务都占用独立线程且长期阻塞的问题,在高并发场景下能更稳定地处理大量重试任务。 - 支持灵活的异步逻辑与任务取消:借助
CompletableFuture可以轻松添加回调、链式处理结果;同时通过ScheduledFuture能随时主动取消重试任务,第一种方案要取消只能通过线程中断,实现成本高且容易出问题。 - 调用与执行解耦,灵活性更强:调用方拿到
CompletableFuture后,既可以选择同步等待结果(get()),也可以异步监听结果,而第一种方案强制调用方同步等待任务结束,无法适配异步业务场景。 - 异常处理更严谨:第一种方案直接吞掉所有异常(空catch块),容易导致问题排查困难;第二种可以通过
CompletableFuture的exceptionally、handle等方法统一处理异常,避免异常丢失,也更符合代码规范。
内容的提问来源于stack exchange,提问作者stlew
相关产品推荐
相关产品推荐

