2009-07-30 10 views
1

可能性の重複:How do you kill a thread in Java?長いタスクをしているループの中にあるときにスレッドを中断する方法は?


私がスレッドに割り込み信号を送信することにより、いくつかの大きな課題をやって停止する必要があります。 java.util.concurrent。*のほとんどのAPIを使用しています。私の仕事はスレッドに送られて実行されます。この作業はクライアントから行われるので、そのコードを制御することはできません。私は基本的には、割り込み信号を受信したときに(私は内部Thread.interrputed()のロジックを置くことはできませんのでご注意下さいforループをループ停止したい

public class Task1 extends Thread { 
    public void run() { 
     while(true){ 
      if(Thread.interrupted()){ 
       return; 
      } 
      for(int i=0; i<Integer.MAX_VALUE; i++){ 
       System.out.println("I am task 1 " + i); 
      } 

     } 
    } 
}; 

タスクに似たものですクライアントから来るので-loop)このタスクを実行するためにExecutorを使用する別のクラスがあります。

public class ConcurrentTest { 

public static void main(String[] args) { 
    // TODO Auto-generated method stub 

    ConcurrentTest test = new ConcurrentTest(); 
    ExecutorService executorService = Executors.newFixedThreadPool(2); 

    Task1 task1 = new Task1(); 
    Future<?> runningTask1 = executorService.submit(task1); 

    Task2 task2 = new Task2(); 
    Future<?> runningTask2 = executorService.submit(task2); 

    //Stop First task after 5 second 
    try { 
     TimeUnit.SECONDS.sleep(5); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    runningTask1.cancel(Boolean.TRUE); 
    System.out.println("runningTask1.isDone is " + runningTask1.isDone()); 
    System.out.println("runningTask1.isCancelled is " + runningTask1.isCancelled()); 
    //Stop Second task after 10 second 
    try{ 
     TimeUnit.SECONDS.sleep(3); 
    }catch(InterruptedException e){ 
     e.printStackTrace(); 
    } 
    runningTask2.cancel(Boolean.TRUE); 
    System.out.println("runningTask2.isDone is " + runningTask2.isDone()); 
    System.out.println("runningTask2.isCancelled is " + runningTask2.isCancelled()); 
} 

}

Task2のは、次のとおり

public class Task2 extends Thread{ 
    public void run() { 
     while(true){ 
      if(Thread.interrupted()){ 
       return; 
      } 
      System.out.println("I am task 2"); 
     } 
    } 
}; 

Task2のがinterrptedさしかしながらタスク1が中断決してとforループ内の実行を続けます。私はクライアントコードの中に何らかのロジックを置くことができません(for-loopに似たもの)。私はこの問題を解決するためにSOコミュニティからの助けが必要です。ありがとう。

+0

スレッド1のforループにThread.interruptedのチェックを入れることができない理由を教えてください。 – RossFabricant

答えて

0

whileループとforループの中で割り込みが2回起こっていないか確認してください。

  while(true){ 
        if(Thread.interrupted()){ 
          return; 
        } 
        for(int i=0; i<Integer.MAX_VALUE; i++){ 
         if(Thread.interrupted()){ 
           return; 
         } 

         System.out.println("I am task 1 " + i); 
        } 

      } 
+0

"forループ内にThread.interrputed()ロジックを置くことはできません。 – erickson

+0

はい、私はクライアントから来るように(ここではforループのような)タスクを制御できません。 – royalGhost

+0

何ができるかは、実行中のスレッドの状態を定期的にチェックする別のスレッドを作成し、必要に応じて強制的に終了させるためにstop()(err ...廃止されましたがまだ動作します)しかし、これは非常に危険で醜いです。スレッドが共有リソースを使用しており、終了すると、スレッドがクリーンアップなしで終了したため、誰もその共有リソースにアクセスできなくなるため、アプリケーションにデッドロックが発生する可能性があります。残念ながら、私はこれにエレガントな解決策が表示されません。 –

0

他の誰かがワーカースレッド(jar?)でコードを提供している場合、彼らは自分のコードを自分の仕事の一環として呼び出しますか?これらの関数が中断しているかどうかをチェックして、関数が呼び出すことを記述し、スレッドを終了させる未確認の例外をスローすることができます。

// Called from the worker thread code that someone else writes, 
// hopefully often so that we notice when we're interrupted. 
public void doSomething() { 
    if (Thread.interrupted()) { 
    throw new MyRuntimeException(); 
    } 
    // do what this method is meant to do ... 
} 

このコードを書いている開発者には注意してください。this article describing some of the problems that can ariseを参照してください。

つまり、コードを書いていないのであれば、誰もがThread.interrupted()をチェックして正常に終了できるようにすることをお勧めします。

1

中断は実際には協調キャンセルメカニズムではなく、先制攻撃である。それは、優雅なキャンセルを行うという仕事からの協力を必要とします。タスクが中断できない場合(つまり、割り込みステータスをチェックしたり、InterruptedExceptionに応答してアクションを中止しない場合)、タスクをキャンセルすることはあまりありません。割り込みを提供するのは簡単です。それは本当にタスクがそれにどのように反応するかです。

可能な解決策の1つは、ダイナミック計装などの方法でコードにタスクを注入することです。しかし、それでも確かな賭けではなく、タスクがwhileループを使用する場合、whileループの内部にコードを注入する必要があります。

1

私は、クライアントコードが停止信号を協力して処理できるようにするメカニズムを提供します。クライアントコードがシグナルを処理する場合、アプリケーションとクライアントはタイムリーに停止することに同意します。それ以外の場合は、コードがinterrupted()チェックに戻るときにスレッドを中断します。私のポイントは、あなたが盲目的にそれを中断するのではなく、協調的であるようにクライアントコードに頼むべきです。

3

唯一の爆発防止ソリューションは、クライアント提供のコードをアイソレートで実行することです。アイソレートは基本的に、Javaアプリケーションが作成、管理、通信できるプライベート仮想マシンです。特に、親アプリは隔離子とすべてのスレッドを安全に殺すことができます。

参考:JSR-000121 Application Isolation API Specification - Final Release

問題は、分離株をサポートしてJVMを見つけることです。

0

スレッドを停止する簡単な方法は、各スレッドに対して停止フラグを定義し、定期的にそのフラグを確認することです。例えば

class MyTask implements Runnable { 
    private AtomicBoolean stopflag = new AtomicBoolean(); 
    public void stop() { 
     stopflag.set(true); 
    } 

    public void run() { 
     while(true) { 
      if(!stopflag.get()) 
       /// do some work 
      else 
       return; // get out 
     } 
    } 
} 
2

ご質問を再読み込みして、タスクのコードを制御することはできません実現。

task1が中断しないのは、interrupt()メソッドが実際に何かを中断しないということです。ロックまたはスリープ中にそのスレッドが待機している場合にのみスレッドが中断します。そうでなければ、ステータスの設定以外は何もしないでください。

task1をkillする唯一の方法は、Thread.stop()メソッドを使用することです。 非常に危険でシステムが不安定になることがありますが、注意してください。 続きを見るhere

2

"停止"フラグとラッパークラスを使用して、自分のタスクとクライアントが提供するタスクの両方を終了することができます。

public class MyTask implements Runnable { 
    private TaskController taskControl; 

    @Override 
    public void run() { 
    if(taskControl.abort()) { 
     return; 
    } 
    // Task logic ... 
    } 
} 

// Construct on main thread, call "run()" on a dedicated background thread. 
public class TaskController implements Runnable { 
    private AtomicBoolean terminate = new AtomicBoolean(false); 
    private ThreadPoolExecutor yourTaskThreadPool; 
    private ThreadPoolExecutor otherTaskThreadPool; 

    @Override 
    public void run() { 
    // Your task construction, dispatch logic. Use your own thread pool 

    // Run the tasks you don't control in THEIR own pool 
    if(terminate.get()) { 
     otherTaskThreadPool.shutdown(); 
    } 
    otherTaskThreadPool.execute(clientsTask); // e.g. "task1" 
    } 

    public void AbortAllTasks() { 
     terminate.set(true); 
    } 

    public boolean abort() { 
     return terminate.get(); 
    } 
} 

あなたのタスクは、建設パラメータとしてコントローラ(「この」ポインタを)取る、そしてそのrun()で終了フラグをチェックすることができます。これにより、TaskController.AbortAllTasks()を呼び出すだけで、すべてを非同期で終了することができます。制御しないタスクの場合は、自分の割り込みロジックをTaskController.run()に入れることができます。

0

forステートメント自体に変更を加えずに変更することはできません。 Sunが即座にスレッドを中断する方法を失ったためです。彼らには理由がありました。 (see here)それを行う唯一の方法は、ループ内でブール値を使用することです。スレッドがforループ内でsleep \ waitを実行すると、Thread.interuppt()によってスローされたInterruptedExceptionを捕捉できます。

関連する問題