Java中进行异步调用失败的解决方法详解

 更新时间:2026年01月13日 09:23:01   作者:程序员大华  
异步编程是一种非阻塞的编程模式,允许程序在等待某个操作完成时继续执行其他任务,而不是一直等待,下面我们就来看看异步调用失败的相关解决方法吧

1.异步编程介绍

什么是异步编程

异步编程是一种非阻塞的编程模式,允许程序在等待某个操作完成时继续执行其他任务,而不是一直等待。

当操作完成后,通过回调函数、Future 或事件通知等方式获取结果。

同步 vs 异步对比:

  • 同步:顺序执行,每一步必须等待前一步完成
  • 异步:非阻塞执行,可以同时处理多个任务

Java 中的异步实现方式

CompletableFuture (Java 8+)

// 创建异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 模拟耗时操作
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "异步任务结果";
});

// 处理结果
future.thenAccept(result -> System.out.println("结果: " + result));

@Async 注解 (Spring Framework)

@Service
public class AsyncService {
    
    @Async
    public CompletableFuture<String> asyncMethod() {
        // 异步执行的方法
        return CompletableFuture.completedFuture("执行结果");
    }
}

回调函数

public interface Callback {
    void onSuccess(String result);
    void onError(Exception e);
}

public void asyncOperation(Callback callback) {
    new Thread(() -> {
        try {
            // 模拟操作
            String result = doSomething();
            callback.onSuccess(result);
        } catch (Exception e) {
            callback.onError(e);
        }
    }).start();
}

2.异步编程中的常见错误

网络相关错误

  • 连接超时
  • 读取超时
  • DNS 解析失败
  • 网络不可达

资源相关错误

  • 内存不足
  • 线程池耗尽
  • 数据库连接超时

业务逻辑错误

  • 远程服务返回错误码
  • 数据格式异常
  • 业务规则校验失败

示例:可能出错的异步方法

public class UnreliableService {
    
    // 模拟不可靠的远程服务调用
    public CompletableFuture<String> callExternalService(String data) {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟随机错误
            double random = Math.random();
            if (random < 0.3) {
                throw new RuntimeException("网络超时");
            } else if (random < 0.6) {
                throw new RuntimeException("服务端错误");
            }
            return "处理结果: " + data;
        });
    }
}

3. 异步重试机制实现

手动重试实现

基础重试逻辑

public class SimpleRetry {
    
    public static <T> CompletableFuture<T> retryAsync(
            Supplier<CompletableFuture<T>> task, 
            int maxAttempts, 
            long delayMs) {
        
        CompletableFuture<T> result = new CompletableFuture<>();
        retryAsync(task, maxAttempts, delayMs, 1, result);
        return result;
    }
    
    private static <T> void retryAsync(
            Supplier<CompletableFuture<T>> task, 
            int maxAttempts, 
            long delayMs, 
            int attempt, 
            CompletableFuture<T> result) {
        
        task.get().whenComplete((response, throwable) -> {
            if (throwable == null) {
                result.complete(response);
            } else if (attempt >= maxAttempts) {
                result.completeExceptionally(throwable);
            } else {
                // 延迟后重试
                CompletableFuture.delayedExecutor(delayMs, TimeUnit.MILLISECONDS)
                    .execute(() -> retryAsync(task, maxAttempts, delayMs, attempt + 1, result));
            }
        });
    }
}

使用 Spring Retry

添加依赖

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.0</version>
</dependency>

配置重试模板

@Configuration
@EnableRetry
public class RetryConfig {
    
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate template = new RetryTemplate();
        
        // 重试策略:最多重试3次,遇到特定异常时重试
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, 
            Collections.singletonMap(RuntimeException.class, true));
        template.setRetryPolicy(retryPolicy);
        
        // 退避策略:每次重试间隔1秒
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(1000);
        template.setBackOffPolicy(backOffPolicy);
        
        return template;
    }
}

使用 @Retryable 注解

@Service
public class RetryableService {
    
    @Retryable(
        value = {RuntimeException.class},
        maxAttempts = 3,
        backoff = @Backoff(delay = 1000)
    )
    @Async
    public CompletableFuture<String> retryableAsyncMethod() {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟可能失败的操作
            if (Math.random() < 0.7) {
                throw new RuntimeException("临时错误");
            }
            return "成功结果";
        });
    }
    
    @Recover
    public CompletableFuture<String> recover(RuntimeException e) {
        return CompletableFuture.completedFuture("降级结果");
    }
}

高级重试策略实现

指数退避重试

public class ExponentialBackoffRetry {
    
    public static <T> CompletableFuture<T> retryWithExponentialBackoff(
            Supplier<CompletableFuture<T>> task,
            int maxAttempts,
            long initialDelay,
            long maxDelay) {
        
        return retryWithExponentialBackoff(task, maxAttempts, initialDelay, maxDelay, 1);
    }
    
    private static <T> CompletableFuture<T> retryWithExponentialBackoff(
            Supplier<CompletableFuture<T>> task,
            int maxAttempts,
            long initialDelay,
            long maxDelay,
            int attempt) {
        
        CompletableFuture<T> future = task.get();
        
        if (attempt >= maxAttempts) {
            return future;
        }
        
        return future.handle((result, throwable) -> {
            if (throwable == null) {
                return CompletableFuture.completedFuture(result);
            } else {
                // 计算退避时间
                long delay = Math.min(maxDelay, initialDelay * (long) Math.pow(2, attempt - 1));
                
                // 添加随机抖动避免惊群效应
                delay = (long) (delay * (0.5 + Math.random()));
                
                CompletableFuture<T> nextAttempt = CompletableFuture
                    .delayedExecutor(delay, TimeUnit.MILLISECONDS)
                    .supplyAsync(() -> 
                        retryWithExponentialBackoff(task, maxAttempts, initialDelay, maxDelay, attempt + 1)
                    )
                    .thenCompose(cf -> cf);
                
                return nextAttempt;
            }
        }).thenCompose(cf -> cf);
    }
}

基于条件的重试

public class ConditionalRetry {
    
    public static <T> CompletableFuture<T> retryWithCondition(
            Supplier<CompletableFuture<T>> task,
            Predicate<Throwable> shouldRetry,
            int maxAttempts,
            Function<Integer, Long> delayCalculator) {
        
        CompletableFuture<T> result = new CompletableFuture<>();
        retryWithCondition(task, shouldRetry, maxAttempts, delayCalculator, 1, result);
        return result;
    }
    
    private static <T> void retryWithCondition(
            Supplier<CompletableFuture<T>> task,
            Predicate<Throwable> shouldRetry,
            int maxAttempts,
            Function<Integer, Long> delayCalculator,
            int attempt,
            CompletableFuture<T> result) {
        
        task.get().whenComplete((response, throwable) -> {
            if (throwable == null) {
                result.complete(response);
                return;
            }
            
            boolean canRetry = attempt < maxAttempts && shouldRetry.test(throwable);
            
            if (!canRetry) {
                result.completeExceptionally(throwable);
                return;
            }
            
            long delay = delayCalculator.apply(attempt);
            CompletableFuture.delayedExecutor(delay, TimeUnit.MILLISECONDS)
                .execute(() -> 
                    retryWithCondition(task, shouldRetry, maxAttempts, delayCalculator, attempt + 1, result)
                );
        });
    }
}

完整的重试工具类

public class AsyncRetryUtil {
    
    /**
     * 异步重试执行器
     */
    public static class AsyncRetryBuilder<T> {
        private final Supplier<CompletableFuture<T>> task;
        private int maxAttempts = 3;
        private Predicate<Throwable> retryCondition = ex -> true;
        private Function<Integer, Long> delayStrategy = attempt -> 1000L * attempt;
        private Consumer<Integer> onRetry = attempt -> {};
        private Function<Throwable, T> fallback = null;
        
        private AsyncRetryBuilder(Supplier<CompletableFuture<T>> task) {
            this.task = task;
        }
        
        public static <T> AsyncRetryBuilder<T> of(Supplier<CompletableFuture<T>> task) {
            return new AsyncRetryBuilder<>(task);
        }
        
        public AsyncRetryBuilder<T> maxAttempts(int maxAttempts) {
            this.maxAttempts = maxAttempts;
            return this;
        }
        
        public AsyncRetryBuilder<T> retryIf(Predicate<Throwable> condition) {
            this.retryCondition = condition;
            return this;
        }
        
        public AsyncRetryBuilder<T> delayStrategy(Function<Integer, Long> strategy) {
            this.delayStrategy = strategy;
            return this;
        }
        
        public AsyncRetryBuilder<T> onRetry(Consumer<Integer> callback) {
            this.onRetry = callback;
            return this;
        }
        
        public AsyncRetryBuilder<T> fallback(Function<Throwable, T> fallback) {
            this.fallback = fallback;
            return this;
        }
        
        public CompletableFuture<T> execute() {
            CompletableFuture<T> result = new CompletableFuture<>();
            execute(1, result);
            return result;
        }
        
        private void execute(int attempt, CompletableFuture<T> result) {
            task.get().whenComplete((response, throwable) -> {
                if (throwable == null) {
                    result.complete(response);
                    return;
                }
                
                boolean shouldRetry = attempt < maxAttempts && retryCondition.test(throwable);
                
                if (!shouldRetry) {
                    if (fallback != null) {
                        try {
                            T fallbackResult = fallback.apply(throwable);
                            result.complete(fallbackResult);
                        } catch (Exception e) {
                            result.completeExceptionally(e);
                        }
                    } else {
                        result.completeExceptionally(throwable);
                    }
                    return;
                }
                
                onRetry.accept(attempt);
                long delay = delayStrategy.apply(attempt);
                
                CompletableFuture.delayedExecutor(delay, TimeUnit.MILLISECONDS)
                    .execute(() -> execute(attempt + 1, result));
            });
        }
    }
}

使用示例

public class RetryExample {
    
    public static void main(String[] args) throws Exception {
        // 模拟不可靠的服务
        Supplier<CompletableFuture<String>> unreliableService = () -> 
            CompletableFuture.supplyAsync(() -> {
                double rand = Math.random();
                if (rand < 0.8) {
                    throw new RuntimeException("服务暂时不可用");
                }
                return "服务调用成功";
            });
        
        // 使用重试工具
        CompletableFuture<String> result = AsyncRetryUtil.AsyncRetryBuilder
            .of(unreliableService)
            .maxAttempts(5)
            .retryIf(ex -> ex.getMessage().contains("暂时不可用"))
            .delayStrategy(attempt -> 1000L * attempt) // 线性退避
            .onRetry(attempt -> 
                System.out.println("第 " + attempt + " 次重试..."))
            .fallback(ex -> "降级结果")
            .execute();
        
        result.whenComplete((response, error) -> {
            if (error != null) {
                System.out.println("最终失败: " + error.getMessage());
            } else {
                System.out.println("最终结果: " + response);
            }
        });
        
        // 等待异步操作完成
        Thread.sleep(10000);
    }
}

4. 注意事项

重试策略选择

  • 网络超时:使用指数退避 + 随机抖动
  • 服务限流:根据返回的等待时间重试
  • 业务错误:根据具体错误码决定是否重试

避免的问题

  • 无限重试:设置最大重试次数
  • 资源耗尽:合理控制重试频率
  • 雪崩效应:使用断路器模式配合重试
  • 重复操作:确保操作的幂等性

监控和日志

// 添加重试监控
public class RetryMonitor {
    private static final MeterRegistry meterRegistry = new SimpleMeterRegistry();
    
    public static void recordRetry(String operation, int attempt) {
        Counter.builder("retry.attempts")
            .tag("operation", operation)
            .register(meterRegistry)
            .increment();
    }
    
    public static void recordSuccess(String operation, long duration) {
        Timer.builder("retry.duration")
            .tag("operation", operation)
            .tag("status", "success")
            .register(meterRegistry)
            .record(duration, TimeUnit.MILLISECONDS);
    }
}

具体业务场景选择合适的重试策略,提高系统的容错能力和稳定性。

以上就是Java中进行异步调用失败的解决方法详解的详细内容,更多关于Java异步调用的资料请关注脚本之家其它相关文章!

相关文章

  • Java关键字this与super详解用法

    Java关键字this与super详解用法

    这篇文章主要介绍了Java关键字this与super的用法,this与super是类实例化时通往Object类通道的打通者;this和super在程序中由于其经常被隐式的使用而被我们忽略,但是理解其作用和使用规范肯定是必须的。接下来将详述this与super各自的的作用,需要的朋友可以参考一下
    2022-04-04
  • Java程序实现导出Excel的方法(支持IE低版本)

    Java程序实现导出Excel的方法(支持IE低版本)

    下面小编就为大家带来一篇Java程序实现导出Excel的方法(支持IE低版本)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 详解IntelliJ IDEA创建spark项目的两种方式

    详解IntelliJ IDEA创建spark项目的两种方式

    这篇文章主要介绍了详解IntelliJ IDEA创建spark项目的两种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • Java设计模式系列之深入浅出单例模式

    Java设计模式系列之深入浅出单例模式

    设计模式是在大量的实践中总结和理论之后优选的代码结构,编程风格,以及解决问题的思考方式,下面这篇文章主要给大家介绍了关于Java设计模式系列之深入浅出单例模式的相关资料,需要的朋友可以参考下
    2021-09-09
  • Java实战之实现在线小说阅读系统

    Java实战之实现在线小说阅读系统

    本文主要介绍了一个通过Java实现的在线电子书小说阅读系统,文中用到的技术有Layui、Springboot、SpringMVC、HTML、FTP、JavaScript、JQuery等,感兴趣的可以试试
    2022-01-01
  • Eclipse设置断点调试的方法

    Eclipse设置断点调试的方法

    这篇文章主要介绍了Eclipse断点调试的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • 使用java实现云端资源共享小程序的代码

    使用java实现云端资源共享小程序的代码

    这篇文章主要介绍了用java写一个云端资源共享小程序,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • javax.persistence中@Column定义字段类型方式

    javax.persistence中@Column定义字段类型方式

    这篇文章主要介绍了javax.persistence中@Column定义字段类型方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • java 可重启线程及线程池类的设计(详解)

    java 可重启线程及线程池类的设计(详解)

    下面小编就为大家带来一篇java 可重启线程及线程池类的设计(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 用Java实现24点游戏

    用Java实现24点游戏

    喜欢玩游戏的有福啦,文中有非常详细的开发框架,按着框架来实现就好啦.而且24点游戏是经典的纸牌益智游戏.,需要的朋友可以参考下
    2021-05-05

最新评论