- PR -

スレッドの停止の仕方について

投稿者投稿内容
Keisuke
大ベテラン
会議室デビュー日: 2003/10/24
投稿数: 105
投稿日時: 2003-10-29 04:16
> このやりかた(threadScroll = null)でスレッドを止めることができるとは、
> 意外でした。私は今まで見たことがありませんでした。
(threadScroll = null)がスレッドを止めるのではなく、
(threadScroll = null)により、 run メソッドから抜けることで
スレッドが終了します。

Threadクラスの説明に(スレッドが終了するのは)、
「run メソッドの呼び出しから復帰することによって、または run メソッド以外から送られる例外をスローすることによって、デーモンスレッドではないすべてのスレッドが終了した場合 」とあります。
taka
常連さん
会議室デビュー日: 2003/09/22
投稿数: 46
投稿日時: 2003-10-29 08:38
かずくんさん、Kissingerさん、unibonさん、Keisukeさん、ご意見ありがとうございました。

まず、かずくんさんから教えていただいたサイトを拝見させていただきました。その中で、
>whileループの中でsleep(巨大な数)などとしていると、 なかなかbreak文に到達できず
>に、 いつまでたってもスレッドが停止しないということになりかねません。
>こういうときは、Threadオブジェクトのinterruptメソッドを呼べば、
>InterruptedExceptionが強制的に発生し、sleepの待ちが解消されて、 スレッドを終了する
>ことができます。
とされていました。私の場合、whileループの中でsleep(巨大な数)をしているわけではありませんが、スレッドの開始/停止フラグチェックの前後に多少時間がかかる処理があるのでやはり
"InterruptedExceptionの強制的発生"を行うのが妥当でしょうか。

Kissingerさんのご意見では、
>threadへの interruptは、割込んだことを記憶させることができますが、
>現在の処理を直ちに終了させるかどうかは、処理系に依存します。
>どうかそのような違いに依存しない設計をして下さい。
うーん、確かにそうなのでしょうね・・・
しかしかずくんさんから教えていただいたサイトの例(whileループの中でsleep(巨大な数))
の場合、このような止め方しかないような気がします・・・

unibonさんのご意見、
>このやりかた(threadScroll = null)でスレッドを止めることができるとは、
>意外でした。私は今まで見たことがありませんでした。
すみません、これは私の説明不足です。Keisukeさんからもご説明ありましたが、
runメソッド内で(threadScroll = null)を確認しているWhile文がありそこでWhile文から
抜け、runメソッドから抜けるといった意味です。

Keisukeのご意見
>素直に、下記のようにするのがよいのでは。
教えていただいたサイト、拝見しました。
いくつか、スレッドの止め方があった為、Keisukeさんの言わんとしている事を私が理解できたかはわかりませんが、気になる方法として下記の文がありました。
しかし、この文でも例えばstop()メソッド発行後、直にstart()メソッドを発行すると
runメソッド内部の"while (blinker == thisThread)"判定前に、blinkerがNullではなくなりスレッドが停止しないという事は考えられないでしょうか?
private volatile Thread blinker;
 public void start() {
  blinker = new Thread(this);
  blinker.start();
 }

 public void stop() {
  blinker = null;
 }

 public void run() {
  Thread thisThread = Thread.currentThread();
  while (blinker == thisThread) {
  try {
   thisThread.sleep(interval);
  } catch (InterruptedException e){
  }
  repaint();
 }
}


/********************************************************/
私の見解としては、スレッド内部のWhile文なり、If文なりでスレッドの停止確認を行っていて、その判定までに時間のかかる処理(sleep(大きな数))などが行われている場合はinterruptを使うと考えました。


Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-10-29 09:47
こんにちは、Wataです。
引用:

takaさんの書き込み (2003-10-29 08:38) より:
の文でも例えばstop()メソッド発行後、直にstart()メソッドを発行すると
runメソッド内部の"while (blinker == thisThread)"判定前に、blinkerがNullではなくなりスレッドが停止しないという事は考えられないでしょうか?


blinkerには常に最新のスレッドが格納されるため、既に最新でなくなった
スレッドによるwhile (blinker == thisThread)の判定はfalseになります。
ただし、厳密にはblinkerのアクセスに同期が必要です。

Effective Javaで紹介されているスレッド終了の例を以下に紹介します。
コード:

public class StoppableThread extends Thread {
private boolean stopRequested = false;

public void run(){
boolean done = false;

while(!stopRequested() && !done){
... // 必要な処理を行う
}
}
public synchronized void requestStop(){
stopRequested = true;
}
private synchronized boolean stopRequested(){
return stopRequested;
}
}



また、最初に示されたInterruptedExceptionによるループ脱出の例は
sleep中以外にthreadScroll.interrupt()の呼び出しを行った場合、スレッドが
停止せず、threadOnOffメソッドも復帰しなくなるのではないでしょうか?
whileの判定にThread.interrupted()が必要だと思います。
あと、threadOnOff(true)が続けて呼び出された場合にスレッドが複数起動してしまいます。

[ メッセージ編集済み 編集者: Wata 編集日時 2003-10-29 09:49 ]
taka
常連さん
会議室デビュー日: 2003/09/22
投稿数: 46
投稿日時: 2003-10-29 11:48
Wataさん、ご意見ありがとうございました。

>blinkerには常に最新のスレッドが格納されるため
なるほど、わかりました。
この方法だったら、start()メソッドを連続して2回発行しても古いほうのスレッドは
停止しますね。

>最初に示されたInterruptedExceptionによるループ脱出の例は
>sleep中以外にthreadScroll.interrupt()の呼び出しを行った場合、スレッドが
>停止せず、threadOnOffメソッドも復帰しなくなるのではないでしょうか?
threadScroll.interrupt()を発行すると、run()メソッドのtry...catch処理が
catch文へ移るのでスレッドが終了します。
かずくんさんから教えていただいたサイトにも同様のケースが書かれておりました。
Wataさんのご質問を理解していなかったらすみません・・

Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-10-29 12:54
引用:

takaさんの書き込み (2003-10-29 11:48) より:
>最初に示されたInterruptedExceptionによるループ脱出の例は
>sleep中以外にthreadScroll.interrupt()の呼び出しを行った場合、スレッドが
>停止せず、threadOnOffメソッドも復帰しなくなるのではないでしょうか?
threadScroll.interrupt()を発行すると、run()メソッドのtry...catch処理が
catch文へ移るのでスレッドが終了します。


InterruptedExceptionをキャッチする必要があるメソッドは
・Thread.sleep()
・Thread.join()
・Object#wait()
と内部的にこれらを使用する他のメソッドなどです。
つまり、これらのメソッドの実行中しかInterruptedExceptionは発生しませんし、
キャッチすることはできません。
その他の場合は、主にスレッドに割り込みステータスが設定されて、Thread.isInterrupted()
の値がtureになります。
Thread.interrupt()のAPIを確認してみてください。
taka
常連さん
会議室デビュー日: 2003/09/22
投稿数: 46
投稿日時: 2003-10-29 13:53
Wataさん、再度のご意見ありがとうございました。

>InterruptedExceptionをキャッチする必要があるメソッドは
>・Thread.sleep()
>・Thread.join()
>・Object#wait()
>と内部的にこれらを使用する他のメソッドなどです。
>つまり、これらのメソッドの実行中しかInterruptedExceptionは発生しませんし、
>キャッチすることはできません。
>Thread.interrupt()のAPIを確認してみてください。

で、"Thread.interrupt()のAPI"を読んで見ると
>Object クラスの wait()、wait(long)、wait(long, int) メソッドの呼び出し、
>またはこのクラスの join(), join(long)、join(long, int)、sleep(long)、
>または sleep(long, int) メソッドの呼び出しでこのスレッドがブロックされる場合、
>割り込みステータスはクリアされ、InterruptedException を受け取ります。

との事でした。
で、ではなぜ私の"run()"メソッドは"threadScroll.interrupt()"を発行すると
catchへ処理が移動するでしょうか?
たまたま、sleep()処理中だったからでしょうか?





ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-10-29 14:00
ども、ほむらです。
今のところ僕の場合特に問題なかったのですが。。。。
どういった場合に問題が出そうですか?
こんどは省略ナシの形でコード貼り付けます。。。
#紹介されているURLはこれから目を通します^^;;;;
コード:
import java.lang.*;

public class ThreadSample 
{
  CMyThread t;
  ThreadSample(){
    t = null;
  }
  public void ThreadOnOff(boolean sw){
    if( sw == true ){
      if( t != null ) ThreadOnOff( false );
      t = new CMyThread((int)(Math.random() * 1000.0));
      t.start();
    }
    else {
      synchronized(t) {
        t.kill();
        t = null;
      }
    }
  }
  class CMyThread extends Thread
  {
    private boolean bThreadAlive;
    private long lngRandom;
    private int id;
    CMyThread(int id){
      this.id = id;
      bThreadAlive = true;
      lngRandom = (long)(Math.random() * 100.0);
    }
    public void kill(){
      bThreadAlive = false;
    }
    public void run(){
      while( bThreadAlive == true ){
        try{
          System.out.print(Long.toString(lngRandom) + "(" + Integer.toString(this.id) + ")," );
          sleep(350);
         }
        catch(InterruptedException ie){
        }
      }
      System.out.print(Long.toString(lngRandom) + "(" + Integer.toString(this.id) + ")," );
      System.out.println(" END");
    }
  }
  public static void main(String [] argv){
    ThreadSample app = new ThreadSample();
    try {
      app.ThreadOnOff(true);
      Thread.sleep(1020);
      app.ThreadOnOff(false);
      app.ThreadOnOff(true);
      Thread.sleep(520);
      app.ThreadOnOff(false);
      app = null;
     }
    catch( InterruptedException ie ){
    }
  }
}


taka
常連さん
会議室デビュー日: 2003/09/22
投稿数: 46
投稿日時: 2003-10-29 15:08
ほむらさん、ご意見とフルロジックをありがとうございました。

ほむらさんからいただいたロジックを試してみました。
ただ、"public static void main(String [] argv){"の中で
 app.ThreadOnOff(true);
 Thread.sleep(1020);
 app.ThreadOnOff(false);
 app.ThreadOnOff(true);
 Thread.sleep(520);
 app.ThreadOnOff(false);
とされていますが、これを
 app.ThreadOnOff(true);
 app.ThreadOnOff(false);
 app.ThreadOnOff(true);
 app.ThreadOnOff(false);
とすると、"run()"メソッド内の"while( bThreadAlive == true ){"で
行われているフラグ判定が常にFalseとなりWhile文内へ処理が移る事はありません
でした。
そりゃそうだよ!"app.ThreadOnOff(true);"の後にすぐ"app.ThreadOnOff(false);"
してんだから! と言われるかもしれませんが・・・

これって、"class CMyThread"で"bThreadAlive = true;"とされ実際にスレッドが走るまでに
"bThreadAlive = false;"されてしまっているという事ですよね?
だとしたら、この逆で"bThreadAlive = false;"したのにスレッド内While判定文までに
"bThreadAlive = true;"と設定されたらスレッドは止まらないとはなりませんか?






スキルアップ/キャリアアップ(JOB@IT)