4

実行時に2つのスレッドを開始するコードを開発しました

public class MyThread1 extends Thread //extend thread class 
{
    // public  synchronized void run()
     //synchronized (this)

     public   void run()
    {//synchronized(this)
        //{
         for(int i=0;i<20;++i) {
             try{
                 Thread.sleep(500);


          System.out.print(i +"\n"+ "..");
             }catch(Exception e)
             {e.printStackTrace();}
          //} 
        }

     }  

 public static void main(String... a) 
 {
     MyThread1 t = new MyThread1();

     Thread x = new Thread(t);

     Thread y = new Thread(t);
     x.start();
     y.start();

     }

これで両方のスレッドが開始されますが、特定のスレッドを停止したい場合は、スレッド Y を停止したいとします。スレッドを停止すると、スレッドの実行メソッドが完了したことになりますが、停止したいので、どうすればよいか教えてください。強制的にこれを行う方法、アドバイスしてください

4

3 に答える 3

4

免責事項:この回答にはチュートリアルのキャラクターが含まれています。

基本的なアプローチThread.sleep:最初は物事をシンプルに保ち、メソッド中の中断には対処しません。基本的に、runメソッドがループのすべての反復でチェックする外部設定可能な変数が必要です。次に、その変数を設定して、run()メソッドを正常に終了できます。このイディオムがJava以外の言語で簡単に使用できることに注意してください。

例えば:

public class MyThreadedClass extends Thread {

  private volatile boolean completed = false;

  public void setCompleted() {
    this.completed = true;
  }

  public void run()
  {
    while (!completed) {
      // do anything you fashion
    }
  } 

  public static void main(String... args) 
  {
    MyThreadedClass x = new MyThreadedClass();
    MyThreadedClass y = new MyThreadedClass();

    x.start();
    y.start();

    x.setCompleted(); // will complete as soon as the latest iteration finishes

    ...
  }
}

コメント:volatileフラグはcompleted、関数の制御外で変更される可能性がある(および変更される)ことをコンパイラーに通知しrun()ます。つまり、別のスレッドが変更する可能性があります。そうしないと、クラスの唯一の同期動作に従って、ループ内の反復チェックが誤って最適化される可能性があります。

あなたの特定run()のケースでは、forループを利用するので、私たちのアプローチは次のように変換されます。

public void run()
{
  try {
    for(int i=0;i<20 && !completed;++i) {        
      Thread.sleep(500);
      System.out.print(i +"\n"+ "..");
    } 
  } catch(Exception e) {
    e.printStackTrace();
  }
}

コメント:それはかなり明白なので、スリープコールのために最大500ミリまで待たなければならない場合があります。ただし、一般に、コードで変数の状態を変更する操作を実行する必要がある場合(特に、そのような変数が複数のスレッド間で共有されている場合)、このようにして、これらの変数を誤った状態のままにしないでください。実際には、終了を制御するため、トランザクションを適切に処理できます。これは明らかに、ループの各反復の終わりに、変数の状態が一貫していることを前提としています。

ここで、の中断を処理するための基本的なアプローチを改善しましょうThread.sleep

完全な回答:この回答には、呼び出し側からのThread.interrupt()メソッドの使用が含まれます。これにより、アプローチはJavaに厳密に固有になります。

public class MyThreadedClass extends Thread {

  public void run()
  {
    try {
      for(int i=0;i<20 && !this.isInterrupted();++i) {        
        Thread.sleep(500);
        System.out.print(i +"\n"+ "..");
        ...
        // some molassy slow code here, where you may sprinkle isInterrupted()
        // checks and consequent break statements 
      } 
    } catch(InterruptedException e) {
      // do whatever you need to clean things up
    } catch(Exception e) {
      // handle other exceptions as seen fit
    }
  }

  public static void main(String... args) 
  {
    MyThreadedClass x = new MyThreadedClass();

    x.start();

    // will complete 
    // a) as soon as one isInterrupted() check breaks the loop, or 
    // b) "immediately" during the blocking call to sleep()
    x.interrupt(); 

    ...
  }
}

コメント:この場合、あなたはすでにあなたの仕事の半分をスレッド自体によって行っています。通話中に中断するだけでよい場合は、必要に応じて、状態をクリーンアップするためThread.sleepの処理以外のことを行う必要はありません。InterruptedException代わりに、「スロー」コード中に割り込みをかける必要がある場合は、this.isInterrupted()好きな場所(おそらく複数の場所)で呼び出して、ループを中断する必要があります。ループ条件内の呼び出しは一般的ですが、必須ではありません。

詳細については、Java同時実行割り込みのチュートリアルを参照してください。

于 2012-04-29T11:28:52.540 に答える
2

物事をできるだけシンプルに保ちます。

 public class Threads {
    public static class MyRunnable implements Runnable {
        public void run() {
            try {
                for (int i = 0; i < 20; ++i) {
                    Thread.sleep(500);
                    System.out.print(i + "\n" + "..");
                }
            } catch (InterruptedException e) {
                System.out.println("Interrupted");
            }
        }
    }

    public static void main(String... a) throws InterruptedException {
        Thread x = new Thread(new MyRunnable());
        Thread y = new Thread(new MyRunnable());
        x.start();
        y.start();
        Thread.sleep(2000);
        y.interrupt();
        Thread.sleep(2000);
        x.interrupt();
    }
}
于 2012-04-29T13:46:01.113 に答える
2

あなたはinterrupt()スレッドにする必要があります。ブロック呼び出し ( などsleep()) は、スレッドが中断されたときに InterruptedException をスローします。タイトなループでできるだけ早く停止したい場合は、isInterrupted()メソッドを使用して現在のスレッドが中断されているかどうかを定期的に確認してください。

詳細については、Java 同時実行チュートリアルを参照してください。

于 2012-04-29T11:38:43.937 に答える