從 Java 11 切換到 Java 17(從 Ubuntu 20.04 存盤庫安裝 OpenJDK)后,以下代碼不起作用:
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.exception.ExceptionUtils;
public class TestClass {
public static void main(String[] args) {
CompletableFuture<String> streamFuture = CompletableFuture.supplyAsync(() -> {
throw MyException.wrapIfNeeded(new Exception("MyException"));
});
String result = null;
try {
result = streamFuture.get();
} catch (Exception e) {
System.out.println("Exception: " ExceptionUtils.getMessage(e));
}
System.out.println("Result: " Objects.toString(result));
}
static class MyException extends RuntimeException {
private static final long serialVersionUID = 3349188601484197015L;
public MyException(Throwable cause) {
super(cause == null ? null : cause.getMessage(), cause);
}
public static MyException wrapIfNeeded(Throwable e) {
return e instanceof MyException ? (MyException) e : new MyException(e);
}
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
}
有一個問題streamFuture.get()- 它無限掛起。我挖得更深,發現java.util.concurrent.ForkJoinPool里面有一種方法unmanagedBlock(ManagedBlocker blocker),看起來像
/** ManagedBlock for external threads */
private static void unmanagedBlock(ManagedBlocker blocker)
throws InterruptedException {
if (blocker == null) throw new NullPointerException();
do {} while (!blocker.isReleasable() && !blocker.block());
}
并且程式在 do-while 回圈中無限掛起。
編輯:我發現問題是由toString()添加到我的自定義例外類的方法引起的。出于某種原因,它在 Java 11 之后開始成為一個問題
uj5u.com熱心網友回復:
問題是由于ReflectionToStringBuilder.toString使用了封裝的 java API。
我們可以嘗試類似的事情MyException.wrapIfNeeded(new NullPointerException("")).toString()
并且會看到
執行緒“main”中的例外 java.lang.reflect.InaccessibleObjectException:無法使欄位 static final long java.lang.RuntimeException.serialVersionUID 可訪問:模塊 java.base 不會“打開 java.lang”到未命名的模塊 @b4c966a
為什么這會導致無限掛起?
在CompletableFuture.AsyncSupply#run方法中
static final class AsyncSupply<T> extends ForkJoinTask<Void>
implements Runnable, AsynchronousCompletionTask {
...
public void run() {
CompletableFuture<T> d; Supplier<? extends T> f;
if ((d = dep) != null && (f = fn) != null) {
dep = null; fn = null;
if (d.result == null) {
try {
d.completeValue(f.get());
} catch (Throwable ex) {
d.completeThrowable(ex);
}
}
d.postComplete();
}
}
由于MyException被拋出,d.completeThrowable(ex);被呼叫,在這個方法中,它會將例外包裝到CompletionException,這將呼叫Throwablewith MyExceptionas的建構式cause。
public Throwable(Throwable cause) {
fillInStackTrace();
detailMessage = (cause==null ? null : cause.toString());
this.cause = cause;
}
當cause.toString()被呼叫時,它會扔在開頭提到的例外,所以d.completeThrowable(ex);沒有被完全執行,因此,該程式將永遠掛起。
uj5u.com熱心網友回復:
我發現問題是由toString()添加到我的自定義例外類的方法引起的。出于某種原因,它(或更準確地說ReflectionToStringBuilder.toString(this);:)在 Java 11 之后開始成為一個問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/369850.html
上一篇:在Blazor中,`awaitTask.Run(StateHasChanged)`和`awaitInvokeAsync(StateHasChanged)`之間有什么區別?
下一篇:Ping任務將無法完成
