Runnableを-代表団とのCompletableFuture - 例外が委譲クラスで無視されます

ヴィシャル:

CompletableFutureを使用してコードを非ブロックに私のコードを変換しながら、私は問題に直面しています。質問の範囲を最小限に抑えるために、私が作成したサンプル・コード、私はCompletableFutureを使用するときに動作が異なります。問題はCompletableFutureはRunnableを-代表団からの例外を飲み込んであります。

私は自分の元のアプリケーションに必要ないくつかのラッパーコードを提供するのRunnableとExecutorServiceの上部の委任を使用しています。

サンプルコード:

  • MyRunnable:常に例外をスロー私のサンプル実行可能、。

    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 - これはRunnableを周りの代表者とラップロジックがそれに渡された実行可能、および例外処理のためのプレースホルダを委任されます。

    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 - このデリゲートがメソッドを実行します。それはちょうど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 - 私は2つのアプローチを使用しています。CompletableFutureなしExecutorServiceのを使用して - ウェイ1。ウェイ2 - 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());
        }
    }
    

質問: 私はウェイ1()を実行すると、出力されています

    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

あなたは「DelegatingRunnable」のcatchブロックがMyRunnableから提起され、ここで例外をキャッチすることができていることに気づくことができます。私はCompletableFutureを使用して()ウェイ2を使用する場合、私はそれがwhenComplete "コールバックCompletableFutureの下咳される参照もののしかし、MyRunnableからの例外は、DelegatingRunnable下coughtではありません。

ウェイ2の出力があります

    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

あなたはCompletableFutureが内部で同じDelegatingExecutionServiceとDelegatingRunnableを使用していることに気づくことができます。DelegatingRunnable、この場合には、例外をキャッチすることはできませんなぜ私は理解していません。

(なぜ私はCompletableFutureを使用しています - ?これは私が直面しています正確な問題を説明するためだけのサンプルコードですが、全体的に、私は、ノンブロッキングな方法でevantuallyタスクのチェーンを作るためにCompletableFutureを使用する必要があります。)

ヒーローワンダース:

ソースコードではCompletableFuture、あなた、それは与えられたラップことが確認できRunnableた型のオブジェクトにはAsyncRun、それ自体が実装しますRunnableこれはAsyncRunあなたのエグゼキュータのに渡されるexecute方法。インナー/オリジナルの場合はRunnable例外をスローし、それはのコードで引っ掛かりAsyncRunCompletableFuture失敗したとして完成されているが、例外はなりません再スローされます。

あなたのラッパーが(だからこそDelegatingRunnable)例外を見ることはありません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=119934&siteId=1