CompletableFuture con Ejecutable-delegación - excepción es ignorado en la clase delegar

Vishal:

Estoy frente a un problema al convertir el código para no bloqueo código usando CompletableFuture. Para minimizar el alcance de la cuestión, he creado un código de ejemplo que se comporta de forma diferente cuando se utiliza CompletableFuture. La cuestión es CompletableFuture traga la excepción de Ejecutable-delegación.

Estoy usando delegación en la parte superior del Ejecutable y ExecutorService proporcionar alguna código de contenedor requerido en mi solicitud original.

Código de muestra:

  • MyRunnable: Mi ejecutable muestra, que siempre se produce la excepción.

    public class MyRunnable implements Runnable {
    
        @Override
        public void run() {
            System.out.println("This is My Thread throwing exception : " + Thread.currentThread().getName());
            throw new RuntimeException("Runtime exception from MyThread");
        }
    }
    
  • DelegatingRunnable - esto está delegando ejecutable que los delegados y la lógica envoltura alrededor del Ejecutable pasaron a él, y marcador de posición para el manejo de excepciones.

    public class DelegatingRunnable implements Runnable {
    
        private Runnable delegate; 
    
        public DelegatingRunnable(Runnable delegate) {
            this.delegate = delegate;
        }
    
        @Override
        public void run() {
            System.out.println("Delegating Thread start : " + Thread.currentThread().getName());
            try {
                // Some code before thread execution
                delegate.run();
                // Some code after thread execution
            } catch (Exception e) {
                // While using CompletableFuture, could not catch exception here
                System.out.println("###### Delegating Thread Exception Caught : " + Thread.currentThread().getName());
                //throw new RuntimeException(e.getMessage());
            } catch (Throwable t) {
                System.out.println("!!!!!!! Delegating Thread Throwable Caught : " + Thread.currentThread().getName());
            }
            System.out.println("Delegating Thread ends : " + Thread.currentThread().getName());
        }
    
    }
    
  • DelegatingExecutorService - esta delegados ejecutar el método. Simplemente envuelve el ejecutable con DelegatingRunnable.

    public class DelegatingExecutorService extends AbstractExecutorService {
    
        private ExecutorService executor;
    
        public DelegatingExecutorService(ExecutorService executor) {
            this.executor = executor;
        }
    
        @Override
        public void execute(Runnable command) {
            executor.execute(new DelegatingRunnable(command));
        }
    
        // Othere delegating methods
    
    }       
    
  • MainClass - Estoy utilizando dos enfoques. WAY1 - usando ExecutorService sin CompletableFuture. Way2 - usando CompletableFuture

    public class MainClass {
    
        public static void main(String[] arg) {
            //way1();
            way2();
        }
    
        public static void way2() {
            System.out.println("Way:2 # This is main class : " + Thread.currentThread().getName());
    
            ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);
            DelegatingExecutorService executorService = new DelegatingExecutorService(executor);
    
            CompletableFuture.runAsync(new MyRunnable(), executorService)
                .whenComplete((res, ex) -> {
                    if (ex != null) {
                        System.out.println("whenComplete - exception  : " + Thread.currentThread().getName());
                    } else {
                        System.out.println("whenComplete - success  : " + Thread.currentThread().getName());
                    }
                });
    
            executor.shutdown();
            System.out.println("main class completed : " + Thread.currentThread().getName());
        }
    
        public static void way1() {
            System.out.println("Way:1 # This is main class : " + Thread.currentThread().getName());
            ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);
    
            DelegatingExecutorService executorService = new DelegatingExecutorService(executor);
    
            executorService.execute(new MyRunnable());
    
            executor.shutdown();
            System.out.println("main class completed : " + Thread.currentThread().getName());
        }
    }
    

Pregunta: Cuando ejecuto WAY1 (), la salida es

    Way:1 # This is main class : main
    Delegating Thread start : pool-1-thread-1
    This is My Thread throwing exception : pool-1-thread-1
    ###### Delegating Thread Exception Caught : pool-1-thread-1
    main class completed : main
    Delegating Thread ends : pool-1-thread-1

Se puede observar que el bloque de captura de 'DelegatingRunnable' puede detectar la excepción aquí, que se levantó de MyRunnable. Pero si uso Way2 () usando CompletableFuture, a excepción de MyRunnable no es cought bajo DelegatingRunnable, aunque veo que es ser la tos bajo 'whenComplete' de devolución de llamada de CompletableFuture.

Salida del Way2 es

    Way:2 # This is main class : main
    Delegating Thread start : pool-1-thread-1
    This is My Thread throwing exception : pool-1-thread-1
    Delegating Thread ends : pool-1-thread-1
    whenComplete - exception  : main
    main class completed : main

Se puede notar que la CompletableFuture está utilizando el mismo DelegatingExecutionService y DelegatingRunnable internamente. No entiendo por qué DelegatingRunnable no puede detectar la excepción en este caso.

(¿Por qué estoy usando CompletableFuture -? Esto es sólo un código de ejemplo para explicar el problema exacto que estoy enfrentando Pero en general, es necesario utilizar CompletableFuture para hacer la cadena de tarea evantually en forma no bloqueante.)

Héroe Wanders:

En el código fuente de la CompletableFutureque se puede ver que envuelve a la dada Runnableen un objeto del tipo AsyncRunque a su vez pone en práctica Runnable. Esta AsyncRunserá pasado al ejecutor de su executemétodo. Cuando el interno / original, Runnablese produce una excepción, se ve atrapado por el código de AsyncRuny la CompletableFuturese completa como fracasado, pero será la excepción no ser re-lanzado.

Es por eso que el envoltorio ( DelegatingRunnable) nunca verá la excepción.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=119937&siteId=1
Recomendado
Clasificación