Java中進行異步調(diào)用失敗的解決方法詳解
1.異步編程介紹
什么是異步編程
異步編程是一種非阻塞的編程模式,允許程序在等待某個操作完成時繼續(xù)執(zhí)行其他任務,而不是一直等待。
當操作完成后,通過回調(diào)函數(shù)、Future 或事件通知等方式獲取結(jié)果。
同步 vs 異步對比:
- 同步:順序執(zhí)行,每一步必須等待前一步完成
- 異步:非阻塞執(zhí)行,可以同時處理多個任務
Java 中的異步實現(xiàn)方式
CompletableFuture (Java 8+)
// 創(chuàng)建異步任務
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模擬耗時操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "異步任務結(jié)果";
});
// 處理結(jié)果
future.thenAccept(result -> System.out.println("結(jié)果: " + result));
@Async 注解 (Spring Framework)
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethod() {
// 異步執(zhí)行的方法
return CompletableFuture.completedFuture("執(zhí)行結(jié)果");
}
}
回調(diào)函數(shù)
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.異步編程中的常見錯誤
網(wǎng)絡相關錯誤
- 連接超時
- 讀取超時
- DNS 解析失敗
- 網(wǎng)絡不可達
資源相關錯誤
- 內(nèi)存不足
- 線程池耗盡
- 數(shù)據(jù)庫連接超時
業(yè)務邏輯錯誤
- 遠程服務返回錯誤碼
- 數(shù)據(jù)格式異常
- 業(yè)務規(guī)則校驗失敗
示例:可能出錯的異步方法
public class UnreliableService {
// 模擬不可靠的遠程服務調(diào)用
public CompletableFuture<String> callExternalService(String data) {
return CompletableFuture.supplyAsync(() -> {
// 模擬隨機錯誤
double random = Math.random();
if (random < 0.3) {
throw new RuntimeException("網(wǎng)絡超時");
} else if (random < 0.6) {
throw new RuntimeException("服務端錯誤");
}
return "處理結(jié)果: " + data;
});
}
}
3. 異步重試機制實現(xiàn)
手動重試實現(xiàn)
基礎重試邏輯
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 "成功結(jié)果";
});
}
@Recover
public CompletableFuture<String> recover(RuntimeException e) {
return CompletableFuture.completedFuture("降級結(jié)果");
}
}
高級重試策略實現(xiàn)
指數(shù)退避重試
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 {
/**
* 異步重試執(zhí)行器
*/
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 "服務調(diào)用成功";
});
// 使用重試工具
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 -> "降級結(jié)果")
.execute();
result.whenComplete((response, error) -> {
if (error != null) {
System.out.println("最終失敗: " + error.getMessage());
} else {
System.out.println("最終結(jié)果: " + response);
}
});
// 等待異步操作完成
Thread.sleep(10000);
}
}
4. 注意事項
重試策略選擇
- 網(wǎng)絡超時:使用指數(shù)退避 + 隨機抖動
- 服務限流:根據(jù)返回的等待時間重試
- 業(yè)務錯誤:根據(jù)具體錯誤碼決定是否重試
避免的問題
- 無限重試:設置最大重試次數(shù)
- 資源耗盡:合理控制重試頻率
- 雪崩效應:使用斷路器模式配合重試
- 重復操作:確保操作的冪等性
監(jiān)控和日志
// 添加重試監(jiān)控
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);
}
}
具體業(yè)務場景選擇合適的重試策略,提高系統(tǒng)的容錯能力和穩(wěn)定性。
以上就是Java中進行異步調(diào)用失敗的解決方法詳解的詳細內(nèi)容,更多關于Java異步調(diào)用的資料請關注腳本之家其它相關文章!
相關文章
Java程序?qū)崿F(xiàn)導出Excel的方法(支持IE低版本)
下面小編就為大家?guī)硪黄狫ava程序?qū)崿F(xiàn)導出Excel的方法(支持IE低版本)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07
詳解IntelliJ IDEA創(chuàng)建spark項目的兩種方式
這篇文章主要介紹了詳解IntelliJ IDEA創(chuàng)建spark項目的兩種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01
Java實戰(zhàn)之實現(xiàn)在線小說閱讀系統(tǒng)
本文主要介紹了一個通過Java實現(xiàn)的在線電子書小說閱讀系統(tǒng),文中用到的技術有Layui、Springboot、SpringMVC、HTML、FTP、JavaScript、JQuery等,感興趣的可以試試2022-01-01
javax.persistence中@Column定義字段類型方式
這篇文章主要介紹了javax.persistence中@Column定義字段類型方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11

