我在我的一個專案中使用異步編程。在回傳型別為 CompletionStage 的方法之一中,為了進行測驗,我正在模擬一個例外拋出,該例外不會被例外()捕獲。下面是我根據用例創建的一些測驗代碼。
public class TestMain {
TestService service = new TestService();
public static void main(String[] args) throws InterruptedException {
TestMain t = new TestMain();
System.out.println("STARTED: THREAD " Thread.currentThread().getName());
t.execute("test").toCompletableFuture().join();
System.out.println("DONE: THREAD " Thread.currentThread().getName());
}
public CompletionStage<Void> execute(String s) {
System.out.println("EXECUTE: THREAD " Thread.currentThread().getName());
return CompletableFuture.runAsync(() -> {
System.out.println("EXECUTE-ASYNC STARTED: THREAD " Thread.currentThread().getName());
process(s);}).exceptionally(ex->{
System.out.println("EXECUTE-ASYNC EXCEPTIONAL: THREAD " Thread.currentThread().getName());
System.err.println("EXECUTE-ASYNC EXCEPTIONAL-EXCEPTION " ex.toString());
if (ex.getCause()!=null)
System.err.println("EXECUTE-ASYNC EXCEPTIONAL-EXCEPTION CAUSE " ex.getCause().toString());
throw ex instanceof CompletionException ? (CompletionException) ex : new CompletionException(ex);
});
}
private CompletionStage<Void> process(String s) {
System.out.println("EXECUTE-PROCESS: THREAD " Thread.currentThread().getName());
// throw new RuntimeException();
return service.service(s);
}
}
public class TestService {
public CompletionStage<Void> service(String s) {
System.out.println("SERVICE: THREAD " Thread.currentThread().getName());
// throw new RuntimeException();
return preProcess(s).thenCompose(v -> {
System.out.println("SERVICE-PRE PROCESS -> COMPOSE: THREAD " Thread.currentThread().getName());
return process(s);
});
}
private CompletionStage<Void> preProcess(String s) {
System.out.println("SERVICE-PRE PROCESS: THREAD " Thread.currentThread().getName());
// throw new RuntimeException();
return CompletableFuture.completedFuture(null);
}
private CompletionStage<Void> process(String s) {
System.out.println("SERVICE-PROCESS: THREAD " Thread.currentThread().getName());
throw new RuntimeException();
// return CompletableFuture.completedFuture(null);
}
}
當我運行上面給出的代碼時,輸??出顯示 TestMain.execute() 中的 exceptionly() 沒有被呼叫。
實際輸出(當從 TestService.process() 拋出例外時):
STARTED: THREAD main
EXECUTE: THREAD main
EXECUTE-ASYNC STARTED: THREAD ForkJoinPool.commonPool-worker-1
EXECUTE-PROCESS: THREAD ForkJoinPool.commonPool-worker-1
SERVICE: THREAD ForkJoinPool.commonPool-worker-1
SERVICE-PRE PROCESS: THREAD ForkJoinPool.commonPool-worker-1
SERVICE-PRE PROCESS -> COMPOSE: THREAD ForkJoinPool.commonPool-worker-1
SERVICE-PROCESS: THREAD ForkJoinPool.commonPool-worker-1
DONE: THREAD main
但是,如果我在注釋代碼標記的任何其他地方拋出例外,則會呼叫 exceptionly()。下面是一個這樣的例子。
實際輸出(當從 TestService.preProcess() 拋出例外時):期望上述輸出與此類似。
STARTED: THREAD main
EXECUTE: THREAD main
EXECUTE-ASYNC STARTED: THREAD ForkJoinPool.commonPool-worker-1
EXECUTE-PROCESS: THREAD ForkJoinPool.commonPool-worker-1
SERVICE: THREAD ForkJoinPool.commonPool-worker-1
SERVICE-PRE PROCESS: THREAD ForkJoinPool.commonPool-worker-1
EXECUTE-ASYNC EXCEPTIONAL: THREAD main
EXECUTE-ASYNC EXCEPTIONAL-EXCEPTION java.util.concurrent.CompletionException: java.lang.RuntimeException
EXECUTE-ASYNC EXCEPTIONAL-EXCEPTION CAUSE java.lang.RuntimeException
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.RuntimeException
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1643)
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1632)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1067)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1703)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:172)
Caused by: java.lang.RuntimeException
at in.TestService.preProcess(TestService.java:19)
at in.TestService.service(TestService.java:11)
at in.TestMain.process(TestMain.java:34)
at in.TestMain.lambda$0(TestMain.java:22)
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1640)
... 5 more
有人可以幫忙解釋為什么會這樣嗎?我需要在 TestMain.execute().exceptionalally() 中捕獲拋出的例外,以實作我想在這里使用的重試邏輯。
提前致謝。
uj5u.com熱心網友回復:
您正在呼叫一個回傳 aCompletionStage但忽略回傳值的方法:
CompletableFuture.runAsync(() -> {
System.out.println("EXECUTE-ASYNC STARTED: THREAD " Thread.currentThread().getName());
process(s); // return value ignored
})
CompletableFuture.runAsync(…)如果函式/拋出例外,由創建的階段將例外完成Runnable。當您放入方法中時會發生這種throw new RuntimeException();情況process。但在另一種情況下,它不會拋出例外,而是回傳呼叫者忽略的失敗階段。
您可以將代碼更改為
CompletableFuture.runAsync(() -> {
System.out.println("EXECUTE-ASYNC STARTED: THREAD " Thread.currentThread().getName());
process(s).toCompletableFuture().join();
})
不要忽略回傳的階段,或者最好使用您已經在其他地方使用過的模式:
CompletableFuture.completedFuture(null).thenComposeAsync(v -> {
System.out.println("EXECUTE-ASYNC STARTED: THREAD " Thread.currentThread().getName());
return process(s);
})
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/456686.html
上一篇:我可以將CancellationTokenSource.Cancel和CancellationTokenSource.CancelAfter(timeSpan)用于同一任務嗎?
