2016-09-28 13 views
3

私はThreadErrorExceptionではなく)を投げる可能性があるマルチスレッドプロジェクトに取り組んでいます。マルチスレッドでエラーがどのように処理されるかについての確固たる情報が見つからないので、私はいくつかのテストを行うことにしました。結果は矛盾することがあります。Javaはマルチスレッドでエラーをどのように処理しますか?

これは私のテストコードと、コメントの結果です。

public class MultiThreadError { 
    public static class ErrorThrowingRunnable implements Runnable{ 
     private final boolean throwsError; 
     public ErrorThrowingRunnable(boolean throwsError){ 
      this.throwsError = throwsError; 
     } 

     @Override 
     public void run() { 
      try { 
       // Wait between .5 and 1.5 seconds 
       Thread.sleep(500 + new Random().nextInt(1000)); 
      } catch (InterruptedException ex) {} 
      if(throwsError){ 
       throw new Error(Thread.currentThread().getName()); 
      }else{ 
       System.out.println(Thread.currentThread().getName()); 
      } 
     } 
    } 

    public static void regularThreadPool(){ 
     // Crashes individual thread; swallows error 
     ExecutorService threadPool = Executors.newFixedThreadPool(5); 
     threadPool.submit(new ErrorThrowingRunnable(false)); 
     threadPool.submit(new ErrorThrowingRunnable(false)); 
     threadPool.submit(new ErrorThrowingRunnable(false)); 
     threadPool.submit(new ErrorThrowingRunnable(false)); 
     threadPool.submit(new ErrorThrowingRunnable(true)); 
     threadPool.shutdown(); 
    } 

    public static void onDemandThreads(){ 
     // Crashes individual thread; displays error 
     new Thread(new ErrorThrowingRunnable(false)).start(); 
     new Thread(new ErrorThrowingRunnable(false)).start(); 
     new Thread(new ErrorThrowingRunnable(false)).start(); 
     new Thread(new ErrorThrowingRunnable(false)).start(); 
     new Thread(new ErrorThrowingRunnable(true)).start(); 
    } 

    public static void onDemandThreadPool(){ 
     // Same as onDemandThreads() 
     ExecutorService threadPool = Executors.newFixedThreadPool(5); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(true)); 
     threadPool.shutdown(); 
    } 

    public static void tooSmallThreadPool(){ 
     // When an error is thrown, apparently the thread that threw 
     // the error is not reused, reducing the pool size 
     ExecutorService threadPool = Executors.newFixedThreadPool(3); 
     threadPool.execute(new ErrorThrowingRunnable(true)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.execute(new ErrorThrowingRunnable(false)); 
     threadPool.shutdown(); 
    } 
} 

エラーが発生したスレッドが終了し、メッセージを表示していることが予期されたものと思われます。 RunnableExecutorServicesubmit(Runnable)を使用して渡されたときには、エラーを処理しないRunnableFuture<Void>にラップされていますが、何らかの理由で直接execute(Runnable)を呼び出す以外にこの動作を変更する方法が見つからないことが判明しています同じ挙動を示す。

これには「ベストプラクティス」がありますか?スレッドがエラーをスローする可能性がある場合は、submitをExecutorServiceに送信し、エラーを取り込まない方法がありますか?

+0

ウィースタイルのノートでは、「エラー」を投げないようにしてください。彼らはあなたがとにかく対処しようとするべきではない重大な問題(メモリ不足など)を示します。 'Runnable'から何かを投げたい場合は、' RuntimeException'(またはそのサブクラス)を使うべきです。 –

+0

[Java ExecutorServiceタスクから例外を処理する]の可能な複製(0120-18752) –

+1

「RunnableFuture」_handles_エラーちょうど良い。実行可能なすべての呼び出しはtry/finallyでラップされます。あなたは私が疑うエラーメッセージを見ることができないと言っています。 – Gray

答えて

5

はい、あなたの仕事をExecutorServiceに送信し、返された結果を確認してくださいFuture

ExecutorService es = Executors.newFixedThreadPool(1); 

Future<?> result = es.submit(new Runnable() { 
    @Override 
    public void run() { 
     throw new Error("sample error"); 
    } 
}); 

try { 
    result.get(); 
} catch (ExecutionException e) { 
    e.printStackTrace(); 
} 

あなたのスタックトレースが含まれます:使用

java.util.concurrent.ExecutionException: java.lang.Error: sample error 
    at java.util.concurrent.FutureTask.report(Unknown Source) 
    at java.util.concurrent.FutureTask.get(Unknown Source) 
    at jjj.b.B.main(B.java:23) 
Caused by: java.lang.Error: sample error 
    at jjj.b.B$1.call(B.java:18) 
    at jjj.b.B$1.call(B.java:1) 
    at java.util.concurrent.FutureTask.run(Unknown Source) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
    at java.lang.Thread.run(Unknown Source) 
+0

例外をスローするとエラーが発生することは確かですか? – ndm13

+1

@ ndm13はい、 "java.util.concurrent.ExecutionException:java.lang.Error:sample error"です。私は答えを更新しました。 – MGorgon

+1

@ ndm13ここでプレーンなRunnableを使う答えを更新しました。スロー宣言なしでエラーをスローすることができます。 – MGorgon

0

Futureは、現在またはいくつかの点で、それは準備ができているかどうか、あなたの操作を実行した結果を表すオブジェクトであります将来は。一般的には、RunnableではなくCallableExecutorServiceに渡している場合には、結果を得るために将来的にgetメソッドを呼び出すことになります。

Runnable/Callableが例外をスローする場合、これはFutureオブジェクトに反映されます。 getメソッドを呼び出して、Runnableが正常に実行されたかどうかをテストできます。それがクリーンな実行だった場合は、null(この場合は)戻るでしょう。例外がスローされた場合、getExecutionExceptionをスローします。その例外はその原因としてマークされます。

音楽会場でコートチェックのように思ってください。彼らがあなたのコートを失った場合、あなたのコートを求めるチケットが来るまで、彼らはおそらくあなたに言わないでしょう。 Futureはチケットの目的を果たしています。スレッドからスローされたエラーを処理しようとすると

1

不審なユースケースのようです... Javaのドクから

:「エラーが合理的なアプリケーションが試みるべきではない重大な問題を示すThrowableのサブクラスでありますこのようなエラーの多くは異常な状態です。ThreadDeathエラーは、通常の状態でもエラーのサブクラスですが、ほとんどのアプリケーションがエラーをキャッチしようとしないためです。

私がエラーを処理する必要があった唯一の時間は、例外をひどく管理している第三者を使用して、RuntimeExceptionではなくErrorをスローするときです。この特定のケースでは、予期しないアプリケーションのクラッシュを避けるために、Error(またはThrowable)を捕捉する必要があります。

+0

基本的には、RuntimeExceptionをスローし、他のExceptionと同様に扱うことがベストプラクティスです。スレッド内にある場合は、通常はエラーがスローされますが? – ndm13

+1

個人的に私はあなたのコードにエラーを投げるべき理由を見つけることができません。 Errorをスローするサードパーティなど、あなたが責任を負うコードを使用する必要がある場合、質問は 私がそれを捕まえるべきかどうかです。これはケースバイケースの事ですが、その原因が回復可能であれば、あなたはエラーを捕まえることができます。 たとえば、Webアプリケーションが、テンプレートが無効であるためにエラーをスローする速度などのサードパーティを使用しているとします。Webサービスを継続して実行できるため、このエラーをキャッチして処理する必要があります。 –