- - PR -
Executors(ThreadPoolExecutor)でのRuntimeExceptionのキャッチ
1
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2009-02-26 03:53
Java5から新しく追加された「java.util.concurrent」パッケージを使用してスレッド処理の勉強をしています。
いろいろわかってきたところで、 「別スレッドで例外(RuntimeException系)が発生した場合、独自の例外処理を行うにはどうしたらいいのだろう?」 という疑問にかられました。そこで、以下のようなプログラムを組んでみたのですが、どうにもうまく動作しません。 ※自作の「OrgUncaughtExceptionHandler」クラスの例外対応処理(uncaughtExceptionメソッド)が呼び出されない。 import java.util.*; import java.util.concurrent.*; public class java5_Excecutor { static class Counter implements Runnable { private Thread.UncaughtExceptionHandler p_defUe; public Counter(Thread.UncaughtExceptionHandler defUe) { this.p_defUe = defUe; } public void run() { try { Thread currentThread = Thread.currentThread(); Thread.UncaughtExceptionHandler ue = currentThread.getUncaughtExceptionHandler(); if (ue == null || !(ue instanceof OrgUncaughtExceptionHandler)) { currentThread.setUncaughtExceptionHandler(this.p_defUe); System.out.println(" " + currentThread.getName() + ":設定"); } else { System.out.println(" " + currentThread.getUncaughtExceptionHandler().getClass().getName() + ":確認"); } for (int i = 0; i < 5; i++) { System.out.println(currentThread.getName() + ":" + i); if (i == 3) { System.out.println(" " + currentThread.getName() + ":例外"); throw new RuntimeException(); } Thread.sleep(1000); } } catch (InterruptedException e) { } } } static public void main(String args[]) { ExecutorService ex = null; try { ex = Executors.newFixedThreadPool(1); for (int i = 0; i < 3; i++) { Counter th = new Counter(new OrgUncaughtExceptionHandler()); ex.submit(th); } } finally { ex.shutdown(); } } static class OrgUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + ":キャッチ(" + e.toString() + ")"); } } } いろいろ調べてみたのですが、どうにも手詰まりで…。 何かご存知の方がいらっしゃったら、お知恵を拝借できないでしょうかm(_ _)m |
|
投稿日時: 2009-02-26 08:03
どこを参考にしてこのサンプルを作成したのか解りませんが、ちゃんと解説してある本やページを参考した方がいいと思います。
1. Runnableを使わずにCallable<T> を使用する ⇒ Runnableは戻り値がvoidで例外をthrowsできませんが、Callableは可能 2. submitの戻り値であるFuture<V> を使用する ⇒ http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/concurrent/Task.html ⇒ タスクの実行状態を保持するオブジェクトになります 例外の処理ですが、Futureから結果を取得するときに発生するExecutionExceptionをcatchする事で実現できます。 http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/concurrent/ExecutionException.html |
|
投稿日時: 2009-02-26 19:58
原因がわかりました。
〜原因〜 「java.util.concurrent.FutureTaskクラス」中に定義されているprivate innerクラスである「Syncクラス」の「innerRunメソッド」でThrowableクラスインスタンスがtry〜catchされている為、RuntimeExceptionもcatchされてしまっている為に、自作ハンドラーへ処理が移行しない。 〜わたなべ様〜 ご教授ありがとうございます。m(_ _)m > どこを参考にしてこのサンプルを作成したのか解りませんが、ちゃんと解説してある本やページを参考した方がいいと思います。 おっしゃるとおりだと思います。 そこでなのですが、 「java.util.concurrent」パッケージを使用してスレッド処理を行う場合、 「Threadクラス」にある「setUncaughtExceptionHandlerメソッド」や 「setDefaultUncaughtExceptionHandlerメソッド」を用いた独自例外処理は できません。 その為、「java.util.concurrent」パッケージを使用してスレッド処理を 行い独自例外処理を実装する場合、 ・Callableを使用し処理結果(Future)から例外有無を判断し処理 ・ThreadPoolExecutorクラスを継承した独自ThreadPoolExecutorクラスを 定義し、afterExecuteメソッドをオーバーライドし例外有無を判断し処理 といった方法があげられます。 といった感じで解説されているようなサイト/本をご存知であれば教えて頂けないでしょうか? 少し余談になるのですが、今回、私がどうやって原因を調べたのかというと、JDKに付属されているソース(src.zip)を追いかけて原因を特定しました。 あまり、ソースを読むのは得意でないため、結構、時間がかかってしまったのですが、わたなべ様はどのように調べたりされていますか? もしよろしければ、あわせてご教授して頂けないでしょうか? m(_ _)m 引き続き、今回の問題をクリアしたサンプルを作成したいと思います。 |
|
投稿日時: 2009-02-26 20:45
Java並行処理プログラミング ―その「基盤」と「最新API」を究める
http://www.amazon.co.jp/Java%E4%B8%A6%E8%A1%8C%E5%87%A6%E7%90%86%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E2%80%95%E3%81%9D%E3%81%AE%E3%80%8C%E5%9F%BA%E7%9B%A4%E3%80%8D%E3%81%A8%E3%80%8C%E6%9C%80%E6%96%B0API%E3%80%8D%E3%82%92%E7%A9%B6%E3%82%81%E3%82%8B%E2%80%95-Brain-Goetz/dp/4797337206/ref=sr_1_1?ie=UTF8&s=books&qid=1235648555&sr=8-1 concurrentフレームワークの開発者の本です。 並列処理に関しての基礎知識も含めて結構なボリュームですが、一読する価値のある本かと思います |
|
投稿日時: 2009-02-27 01:10
〜わたなべ様〜
ご回答ありがとうございます。m(_ _)m 教えて頂いた本は是非、読んでみたいと思います。 ※どうも、どこにも在庫がないようですが…orz... 自分がやりたかったことができたので、そのサンプルをアップします。 【やりたかったこと】 ・「java.util.concurrent」パッケージを使用し並行処理を行う。 ・並行処理中に例外が起こった場合、独自に定義した例外処理を実行する。 【サンプル】 import java.util.*; import java.util.concurrent.*; public class java5_Excecutor { static final private int LENGTH = 10; static public void main(String args[]) { /** * Callable経由 * 独自例外処理を実行することができる。 * 処理結果を受け取ることができる。 */ sample1(); /** * Runnable経由 * 独自例外処理を実行することができる。 * 処理結果を受け取ることができない。 * スレッド起動時に引数を設定し、実行後、引数として設定した値を受け取ることができる。 */ sample2(); } static public void sample1() { ExecutorService ex = null; CompletionService<Integer> cs = null; try { ex = Executors.newFixedThreadPool(LENGTH); cs = new ExecutorCompletionService<Integer>(ex); for (int i = 0; i < LENGTH; i++) { cs.submit(new RandomWaitCall()); System.out.println("スレッド起動完了"); } for (int i = 0; i < LENGTH; i++) { Future<Integer> f = cs.take(); try { int r = f.get(); System.out.println("処理結果:" + r); } catch (ExecutionException ee) { System.out.println(" スレッド中で例外が発生しました。(" + ee.getCause().toString() + ")"); } } } catch (InterruptedException ie) { System.out.println(" 割り込みエラーです。"); } finally { ex.shutdown(); } } static class RandomWaitCall implements Callable<Integer> { public Integer call() throws Exception { // 0〜5までで乱数を生成 int r = (int)(Math.random() * 6); if (r == 0) { // 0の場合は擬似的に例外を発生させる。 throw new RuntimeException("0が選択されました。(" + r + ")"); } Thread.sleep(r * 1000); return r; } } static public void sample2() { ExecutorService ex = null; CompletionService<Integer> cs = null; try { ex = Executors.newFixedThreadPool(LENGTH); cs = new ExecutorCompletionService<Integer>(ex); for (int i = 0; i < LENGTH; i++) { cs.submit(new RandomWaitRun(), i); System.out.println("スレッド起動完了"); } for (int i = 0; i < LENGTH; i++) { Future<Integer> f = cs.take(); try { int r = f.get(); System.out.println("呼出引数:" + r); } catch (ExecutionException ee) { System.out.println(" スレッド中で例外が発生しました。(" + ee.getCause().toString() + ")"); } } } catch (InterruptedException ie) { System.out.println(" 割り込みエラーです。"); } finally { ex.shutdown(); } } static class RandomWaitRun implements Runnable { public void run() { // 0〜5までで乱数を生成 int r = (int)(Math.random() * 6); if (r == 0) { // 0の場合は擬似的に例外を発生させる。 throw new RuntimeException("0が選択されました。(" + r + ")"); } try { Thread.sleep(r * 1000); } catch(InterruptedException ie) { throw new RuntimeException("スリープ中に例外が発生しました。"); } return; } } } |
|
投稿日時: 2009-02-28 23:29
〜わたなべ様〜
ご教授頂いた書籍をなんとか入手すことができました。 目から鱗が沢山です。本当にありがとうございました。 ただ、私には理解しかねるような難しい箇所が複数あり、それでも、なんとか読み進めているのですが、自分の理解が正しいか自信がありません...。 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=48422&forum=12&0 ↑新しくスレッドを建て2つ質問しております。 もしよろしければ、ご意見を頂戴できないでしょうか? |
1