Javaサブスレッドによる異常処理方法(共通)


通常のシングルスレッドプログラムでは、異常を捕獲するにはtry...catch...finally...コードブロックだけでいいです。併発の場合、例えば親スレッドにおいて子スレッドが起動していますが、親スレッドに子スレッドからの異常がどのように捕獲され、対応する処理が行われますか?
よくあるエラー
簡単だと思う人もいるかもしれませんが、直接にスレッドを立てるところでtry...catchを使えばいいです。実はこれは違います。
原因分析
Runnableインターフェースのrunメソッドの完全な署名を思い出してみましょう。throws文が表示されていないので、方法はchecedを投げません。RuntimeExceptionのようなunchecked異常については、新しいスレッドはJVMでスケジュール実行されますので、異常が発生したら親スレッドにも通知されません。
public abstract void run()
解決策
では、親スレッドに子スレッドからの異常をどのように捉えますか?ビルの主人は3種類の常用方法を思い付いて、みんなに分かち合います。
方法1:子スレッド中try…catch…
最も簡単で効果的な方法は、子スレッドの方法で、異常が発生する可能性のあるところをtry...catch...という語句でくるむことです。サブスレッドコード:

public class ChildThread implements Runnable {
 public void run() {
  doSomething1();
  try {
   //          
   exceptionMethod();
  } catch (Exception e) {
   //     
   System.out.println(String.format("handle exception in child thread. %s", e));
  }
  doSomething2();
 }
}
方法2:スレッドのための異常プロセッサユニットException Handlerを設定します。
スレッドに異常プロセッサを設定します。具体的なやり方は以下の通りです。
(1)Thread.set Unicaght Exception Handler現在のスレッドの異常プロセッサを設定する
(2)Thread.set Default UnicaghtException Handlerはプログラム全体にデフォルトの異常プロセッサを設定します。現在スレッドに異常プロセッサがある場合(デフォルトではない)、このUnicaghtException Handler類を優先的に使用します。そうでなければ、現在スレッドが属するスレッドグループに異常プロセッサがある場合は、スレッドグループのException Handlerを使用する。そうでなければ、グローバルデフォルトのDefault Uncaght Exception Handlerを使用します。全部ないと、子スレッドは終了します。
注意:サブスレッドに異常が発生しました。何かの種類がなければ、直接に終了します。ログを残して印刷しません。だから、何もしないと、サブスレッドのタスクは実行されていないし、ログのヒントもない「怪しい」現象が発生します。
現在のスレッドの異常プロセッサを設定します。

public class ChildThread implements Runnable { 
 private static ChildThreadExceptionHandler exceptionHandler;

 static {
  exceptionHandler = new ChildThreadExceptionHandler();
 }

 public void run() {
  Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler);
  System.out.println("do something 1");
  exceptionMethod();
  System.out.println("do something 2");
 }

 public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
   System.out.println(String.format("handle exception in child thread. %s", e));
  }
 }
}
または、すべてのスレッドのデフォルト異常プロセッサを設定します。

public class ChildThread implements Runnable {
 private static ChildThreadExceptionHandler exceptionHandler;

 static {
  exceptionHandler = new ChildThreadExceptionHandler();
  Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
 }

 public void run() {
  System.out.println("do something 1");
  exceptionMethod();
  System.out.println("do something 2");
 }

 private void exceptionMethod() {
  throw new RuntimeException("ChildThread exception");
 }

 public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
   System.out.println(String.format("handle exception in child thread. %s", e));
  }
 }
}
コマンドライン出力:ドsomething 1
handle exception in child thread.java.lang.RuntimeException:Child Thread exception
方法三、Futureのget方法で異常を捕捉する。
スレッド池を使って返信情報を得る方法、つまりExectorService.submit(Callable)はsubmitの後にスレッド実行結果を得ることができるFutureオブジェクトを提出しますが、サブスレッドに異常が発生した場合は、future.get()を介して返却値を取得した場合は、Execution Exception Excetion異常を捕捉することができます。
サブスレッドコード:

public class ChildThread implements Callable {
 public Object call() throws Exception {
  System.out.println("do something 1");
  exceptionMethod();
  System.out.println("do something 2");
  return null;
 }

 private void exceptionMethod() {
  throw new RuntimeException("ChildThread1 exception");
 }
}
親スレッドコード:

public class Main {
 public static void main(String[] args) {
  ExecutorService executorService = Executors.newFixedThreadPool(8);
  Future future = executorService.submit(new ChildThread());
  try {
   future.get();
  } catch (InterruptedException e) {
   System.out.println(String.format("handle exception in child thread. %s", e));
  } catch (ExecutionException e) {
   System.out.println(String.format("handle exception in child thread. %s", e));
  } finally {
   if (executorService != null) {
    executorService.shutdown();
   }
  }
 }
}
コマンドライン出力:ドsomething 1
handle exception in child thread.java.util.co ncurrent.Execution Exception:java.lang.RuntimeException:Child Thread 1 exception
締め括りをつける
上には三つのよく使われているJava子スレッドの異常処理方法があります。実はビル主はまたその他のいくつかの特定のシーンの下の解決方法を思い付いて、日を改めて更に分析して、みんなに支持されてありがとうございます。
このJava子スレッドにおける異常処理方法(共通)は、小編集が皆さんに提供しているすべての内容を共有しています。参考にしていただければと思います。どうぞよろしくお願いします。