首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Java17中从CompletableFuture抛出异常挂起get()和join()

在Java17中从CompletableFuture抛出异常挂起get()和join()
EN

Stack Overflow用户
提问于 2021-11-25 13:25:10
回答 2查看 208关注 0票数 5

在我从Java11切换到Java17(从Ubuntu20.04库安装的OpenJDK)后,以下代码不起作用:

代码语言:javascript
复制
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)方法,它看起来像

代码语言:javascript
复制
    /** 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()方法引起的。由于某种原因,它在Java11之后开始成为一个问题

EN

回答 2

Stack Overflow用户

发布于 2021-11-25 15:52:53

该问题是由于ReflectionToStringBuilder.toString使用封装的java API造成的。

我们可以尝试像MyException.wrapIfNeeded(new NullPointerException("")).toString()这样的东西,然后看看

线程"main“java.lang.reflect.InaccessibleObjectException:中的

异常无法使字段静态最终长java.lang.RuntimeException.serialVersionUID可访问:模块java.base不能对未命名的模块@b4c966a”打开java.lang“

为什么这个事业会无休止地悬而未决?

CompletableFuture.AsyncSupply#run方法中

代码语言:javascript
复制
    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,后者将调用Throwable的构造函数,并将MyException作为cause

代码语言:javascript
复制
    public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }

cause.toString()被调用时,它将抛出前面提到的异常,因此d.completeThrowable(ex);没有完全执行,因此程序将永远挂起。

票数 7
EN

Stack Overflow用户

发布于 2021-11-25 15:31:39

我发现这个问题是由添加到自定义异常类中的toString()方法引起的。由于某些原因(或者更准确地说:ReflectionToStringBuilder.toString(this);)在Java11之后开始成为一个问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70111913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档