6

私はJavaを学び始め、現在は並行性の章にいます。並行性についていくつか読んだ後、私は自分の例を試しました。

public class Task implements Runnable{

public void run() {
    while(!Thread.interrupted()) {
        try {
            System.out.println("task");
            TimeUnit.SECONDS.sleep(2);
        }catch (InterruptedException e) {
            System.out.println("interrupted");
        }
    }
}

}

public static void main(String[] args) throws Exception {
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new Task());
    TimeUnit.SECONDS.sleep(10);
    exec.shutdownNow();
}

問題は、次の出力が表示されることを期待していたことです。

task
task
task
task
task
interrupted

しかし、これを取得した後、プログラムは閉じるまで印刷を続けます。
だから、私の質問は私が間違っていることですか?プログラムが印刷を続行するのはなぜですか?

4

4 に答える 4

7

エグゼキュータをシャットダウンすると、実行中のタスクを中断して停止しようとします。これにより、InterruptedExceptionがスローされますが、それを飲み込んで続行します。catch句に戻るか、を呼び出してスレッドの中断ステータスをリセットする必要があります。これによりThread.currentThread.interrupt()、中断ステータスがリセットされ、ループが終了します。

于 2011-08-12T17:08:17.977 に答える
4

あなたはまだwhileループにいます、休憩を追加するか、ループから他の方法で。

    catch (InterruptedException e) {
        System.out.println("interrupted");
        break;
    }

Javaでのスレッド化は一種の協調的な活動であり、停止するように求められていますが、実際にそれを実行するには十分に礼儀正しくする必要があります。これにより、スレッドは、終了する前にその業務を整理することができます。

SimonとAmirによって詳細に説明されているように、ループの終了条件は驚くほど十分ではありません。

于 2011-08-12T17:05:55.327 に答える
4

並行性に関するJavaチュートリアルの割り込みに関するセクションでは、問題が非常によく説明されています。

割り込みステータスフラグ

割り込みメカニズムは、割り込みステータスと呼ばれる内部フラグを使用して実装されます。Thread.interruptを呼び出すと、このフラグが設定されます。スレッドが静的メソッドThread.interruptedを呼び出して割り込みをチェックすると、割り込みステータスがクリアされます。あるスレッドが別のスレッドの割り込みステータスを照会するために使用する非静的isInterruptedメソッドは、割り込みステータスフラグを変更しません。

慣例により、InterruptedExceptionをスローして終了するメソッドは、そうすると割り込みステータスをクリアします。ただし、割り込みを呼び出す別のスレッドによって、割り込みステータスがすぐに再設定される可能性は常にあります。

したがって、ループ内でInterruptedExceptionをキャッチすると、中断されたステータスはすでにリセットされているため、Thread.interrupted()の次の呼び出しはfalseを返し、whileループを実行し続けます。ループを停止するには、次のオプションがあります。

  • breakループを終了するために使用します
  • returnメソッド全体を終了するために使用します
  • try-catch-blockをwhileループの外側に移動します(Nathan Hughesの提案による)
  • 現在のスレッドでinterrupt()を呼び出して、割り込みフラグを再度設定します
  • 別のブール値を使用してループを制御し、それに応じてキャッチブロックでそのフラグを設定します
  • ScheduledExecutorServiceを使用し、のrun-methodからループを削除して、タスクを繰り返しタスクにします。Runnable
于 2011-08-12T17:20:44.873 に答える
1

「アクティブに実行されているタスクの処理を停止するための最善の努力を超える保証はありません。たとえば、通常の実装はThread.interrupt()を介してキャンセルされるため、タスクがマスクされたり、割り込みに応答しなかったりした場合、タスクが終了することはありません。」

ソース:http ://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow ()

于 2011-08-12T17:07:50.410 に答える