- ベストアンサー
スレッドの動作に関する質問
- スレッドが二つ動いている理由を教えてください。
- スレッドを停止して直ぐにまた動かしているのですが、スレッドが二つ動いている理由が分かりません。
- 質問:スレッドがnullの間はrunが動いているロジックですが、停止して直ぐにまた動かしているのになぜスレッドが二つ動いてしまうのでしょうか?
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>調べた所「現在のスレッドに割り込みをする」との事でした。interrupt()をすればそのスレッドは停止されるのでしょうか? InterruptedException を発生させるという事です。 別に例外を起こしたからといってスレッドが停止されるわけではないですよ。只、catch に処理が移動するだけです。 例えば、try~catch が while の中にあれば break でもしない限りは継続して繰返し処理が行なわれます。 外にあれば、while を抜けて catch の処理に移行します。 スレッドは run() メソッドの末端まで処理が進めば役割を終え終了します。 「例外を起す」というと聞こえが悪いように感じるかもしれませんが、interrupt() でのスレッド停止は飽くまでもJava では定石の1つです(逆に stop() 等は非推奨) >stopの度にスレッドにnullを入れないとplayするたびにスレッドがいくつも作られると思ったのですが、いかがでしょうか? そんな事はないのでは? 再度参照されないスレッドはガーベジコレクションの対象となるはずです。 この辺の事はプログラマがやる仕事ではなく、VM の役割ですので気にする事ではないと思いますが。。。 良く参考書では null を入れたりしていますが、これって飽くまでも「お願い」程度の事で、null を入れたら「停止」とか「即廃棄される」わけではないです。
その他の回答 (3)
- takaP-
- ベストアンサー率79% (83/105)
>でtakaP-さんのお知恵を参考に下記のように"stopplay()" >を書き直してみました所、スレッドが2回走るときもあれ >ば大丈夫な時もありました。駄目でしょうか? ダメでしょうね・w 先程、書いた事は、run() メソッドの while を抜けた 後に play() を呼び出せば「何とか」なるという事を 書いた訳でして、改良型(?)stopplay() メソッドでは while を抜ける事は無理。と言う事はスレッドが終わる 事もないということです。 どうしても stop() play() を連続で呼び出したいという のでしたら(必然を理解できませんが)stop() play() の 処理自体を変更するしかないかもしれません。 取り敢えず動く(はず・笑)のソースを載せますので参考 にしてみてください。 class ThreadOnOff implements Runnable { int number ; int counter ; public static void main( String[] args ) { new ThreadOnOff() ; } public ThreadOnOff() { init() ; } public void init() { play() ; } private void play() { Thread thread = new Thread( this, "thread" + number++ ) ; thread.start() ; } private void stop() { Thread.currentThread().interrupt() ; } private void stopplay() { stop() ; play() ; } private String modeRequest() { System.out.println( Thread.currentThread().getName() + " - " + counter++ ) ; if( counter > 9 ) { counter = 0 ; return "STOP Current Thread" ; } else { return "" ; } } public void run() { try { String mode = "" ; while( true ) { Thread.sleep( 500 ) ; mode = modeRequest() ; if( mode.startsWith( "STOP" )) { stopplay() ; } } } catch( InterruptedException ie ) { System.out.println( Thread.currentThread().getName() + " Stop!" ) ; } } } modeRequest() メソッドが10回呼ばれるとスレッドを 停止し、新しいスレッドを起動するサンプルです。
お礼
お礼が遅くなりすみません。 載せていただいたソースは大変参考になりました。 以下に私が思った事を書きましたので、ご意見いただけませんでしょうか? >interrupt() ; を使っていますが、調べた所「現在のスレッドに割り込みをする」との事でした。interrupt()をすればそのスレッドは停止されるのでしょうか? stopの度にスレッドにnullを入れないとplayするたびにスレッドがいくつも作られると思ったのですが、いかがでしょうか?
- takaP-
- ベストアンサー率79% (83/105)
適当にソースを眺めたせいで見落としをしてました。 run() 内の while 構文の判定値に Thread の参照 の有無を指定していたのですね(申し訳ない・謝) Thread のインスタンスに null を代入する事で 停止をしようとしていた、というのは私の誤解です。 では、改めて(汗) 恐らく、run() に記述されている threadOnOff() の呼び出しを、stopplay() の呼び出しに変えた場合 に最初のスレッドが止まらないという事だと想像します。 stopplay() メソッドを呼び出し、stop() が実行され thread 変数に null が代入されたとしても、直ぐに play() メソッドが呼ばれて新たなスレッドが thread インスタンスに代入されてしまいます。 これでは、while の判定値である、thread!=null は 必ず true が帰ってくることになります。 ですので、この方法では stop() play() を連続して 呼び出すのでは目的の動作にはなりません。 一番簡単な方法としては、stop() play() を連続で 呼び出しをしないことです。 例えば while 文で呼び出すのは stop() だけにすると while 文を抜ける事が出来ます。 while 文を抜けた所で play() を呼び出す事により 現在のスレッドは終了し、新しいスレッドだけが動く という動作になります。 public void run(){ while(thread!=null){ try{ // 処理 if(){ stop(); } }catch(){} } play(); }
お礼
お答えありがとうございました。 なぜスレッドが2回走ってしまうかの理由がよくわかりました。 >一番簡単な方法としては、stop() play() を連続で >呼び出しをしないことです。 それが一番よい方法だという事はわかったのですがどうしても連続で呼びたいのです・・・ でtakaP-さんのお知恵を参考に下記のように"stopplay()" を書き直してみました所、スレッドが2回走るときもあれば大丈夫な時もありました。駄目でしょうか? ************************************************* private void stopplay(){ while(threadPlay != null){ try{ stop(); } catch(Exception e){} } play(); }
- takaP-
- ベストアンサー率79% (83/105)
このソースの抜粋では全ての流れを予想するのは 困難な事ですが、基本的なところだけを指摘します。 そもそも、Threadのインスタンス変数にnullを代入 したところでThread自体が停止する事は有りません。 参照が無くなったとしてもスレッドは動き続けます。 (停止後のガーベジコレクション指定には有効) では、どうやってスレッドを止めるかですが、これは 良くある方法として、java.lang.Thread#interrupt() を使うというやり方があります。 interrupt() は「割り込みエラー」を意図的に起して 強制終了させるものです。 上記のソースでは run() メソッド内の try-catch が while 文の内部で記述されていますから、只単に割り込み エラーを発生させても停止にはなりません。 catch 文で break を指定する等の処理をして下さい。 スレッドというのは大変にややこしいもので、今どの スレッドがこれを処理しているのか、ということを何時 でも念頭に置きながらコーディングをしなくては思う様 な動きをしてはくれません。 申し訳ないですが、上記のソースのような記述では狙い 通りのプログラムを作り上げるのは難しいかもしれません。 スレッドに対し、多くの記述を割いている書籍を見付けて じっくりと学習してみる事が一番の近道かもしれません。
お礼
なるほど非常に参考になりました。 まだまだ勉強不足で的外れな質問に丁寧にお答えいただき感謝しています。 本当にありがとうございました。