Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

693
Vistas
Throwing exception from CompletableFuture hangs get() and join() in Java 17

After I have switched from Java 11 to Java 17 (OpenJDK installed from Ubuntu 20.04 repository), the following code doesn't work:

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);
        }
    }
}

There is a problem in streamFuture.get() - it hangs infinitely. I dug deeper and found that in java.util.concurrent.ForkJoinPool there is a method unmanagedBlock(ManagedBlocker blocker) which looks like

    /** ManagedBlock for external threads */
    private static void unmanagedBlock(ManagedBlocker blocker)
        throws InterruptedException {
        if (blocker == null) throw new NullPointerException();
        do {} while (!blocker.isReleasable() && !blocker.block());
    }

and the program hangs infinitely in the do-while loop.

EDIT: I found out the problem is cause by the toString() method added to my custom exception class. For some reason it started to be a problem after Java 11

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

The problem is due to ReflectionToStringBuilder.toString use encapsulated java API.

We can try something like MyException.wrapIfNeeded(new NullPointerException("")).toString() And will see

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field static final long java.lang.RuntimeException.serialVersionUID accessible: module java.base does not "opens java.lang" to unnamed module @b4c966a

Why will this cause hang infinitely?

In CompletableFuture.AsyncSupply#run method

    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();
            }
        }

Since MyException is thrown, d.completeThrowable(ex); is called, inside this method, it will wrap the exception to CompletionException, which will call the constructor of Throwable with MyException as cause.

    public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }

When cause.toString() is called, it will throw the exception mentioned in the beginning, so d.completeThrowable(ex); is not executed completely and hence the program will hang forever.

over 4 years ago · Santiago Trujillo Denunciar

0

I found out the problem is cause by the toString() method added to my custom exception class. For some reason it (or to be more precise: ReflectionToStringBuilder.toString(this);) started to be a problem after Java 11.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda