「こんにちは、アミーゴ!

「新しいものはすべて、私たちが忘れてしまった古いものにすぎません。今日はスレッドの停止について話します。interrupt() メソッドがどのように機能するかをすでに忘れていることを願っています。」

「はい、エリー、すっかり忘れてました。」

「わかりました。では、思い出させていただきます。」

「Java では、誰かが実行中のスレッドを停止したい場合、そのことをスレッドに通知できます。これを行うには、Thread オブジェクトの非表示のisInterrupted変数を trueに設定する必要があります。」

「各スレッドには、このフラグを設定するために使用されるinterrupt() メソッドがあります。interrupt() メソッドが呼び出されると Threadオブジェクト内のisInterrupted変数が true に設定されます。」

「そして、Thread.sleep() または join() メソッドがスレッド上で呼び出されるとき、メソッドは現在のスレッドに isInterrupted フラグが設定されているかどうかを確認します。このフラグが設定されている場合 (変数 isInterrupted が true に等しい)、メソッドInterruptedExceptionをスローします。」

「ここで、古い例を思い出してみましょう。」

コード 説明
class Clock implements Runnable
{
public void run()
{
Thread current = Thread.currentThread();

while (!current.isInterrupted())
{
Thread.sleep(1000);
System.out.println("Tik");
}
}
}
Clock の run メソッドは、現在のスレッドの Thread オブジェクトを取得します。

Clock クラスは、現在のスレッドの isInterrupt 変数が false である限り、「Tick」という単語を 1 秒に 1 回コンソールに書き込みます。

isInterrupt が true になると、run メソッドが終了します。

public static void main(String[] args)
{
Clock clock = new Clock();
Thread clockThread = new Thread(clock);
clockThread.start();

Thread.sleep(10000);
clockThread.interrupt();
}
メインスレッドは、永久に実行されるべき子スレッド (クロック) を開始します。

10 秒待ってから 、割り込みメソッドを呼び出してタスクをキャンセルします。

メインスレッドは作業を終了します。

クロック スレッドは作業を終了します。

「ここでは、 runメソッドの無限ループの一部としてsleepメソッドを使用します。ループ内では、isInterrupt変数が自動的にチェックされます。スレッドがsleepメソッドを呼び出す場合、メソッドはまず、そのスレッドに対してisInterruptが true であるかどうかをチェックします (これが true の場合、メソッドはスリープせず、代わりに InterruptedException をスローします

「しかし、この例では、ループの条件内の isInterrupted 変数を常にチェックしています。」

「このアプローチを使用できなかった理由がいくつかあったことを覚えています。思い出してもらえますか?」

"まずrunメソッドには常にループがあるとは限りません。このメソッドは、他のメソッドへの数十回の呼び出しで構成されているだけかもしれません。この場合、各メソッド呼び出しの前に isInterrupted チェックを追加する必要があります。"

第 2 に、多くのさまざまなアクションを伴う一部のメソッドは、実行に非常に長い時間がかかる可能性があります。」

"第三に、例外のスローは isInterrupted チェックを置き換えるものではありません。これは単なる便利な追加です。スローされた例外により、コール スタックをすぐに runメソッド自体に巻き戻すことができます。"

"第 4 に、sleep メソッドは頻繁に使用されます。この便利なメソッドは、同様に役立つ暗黙的なチェックによって強化されていることがわかりました。まるで誰も特別にチェックを追加していないかのように見えますが、チェックは実際に存在します。これは、次の場合に非常に価値があり ます 。他人のコードを使用しているため、自分でチェックを追加することはできません。」

"第 5 に、追加のチェックによってパフォーマンスが低下することはありません。sleep メソッドを呼び出すということは、スレッドが (スリープ以外) 何もしてはいけないことを意味するため、余分な作業が誰にも迷惑になることはありません。"

「それはまさにあなたが前に言った通りです。」

「それでは、あなたの発言はどうでしょうか。«スレッドが停止されることを保証できる人は誰もいません。スレッド自体を停止できるのはスレッドだけです。」 それについて説明できますか?

"もちろん。"

「以前の Java の初期バージョンでは、スレッドに stop() メソッドがありました。そして、それを呼び出すと、JVM は実際にスレッドを停止しました。しかし、スレッドが JVM の外部で何かを行っていた場合 (たとえば、ファイルへの書き込みや呼び出しなど) OS の機能)がこのように中断されると、ファイルが閉じられなかったり、システム リソースが解放されなかったりするなど、中断によって多くの問題が発生しました。」

「Java 作成者の総会で、スレッドを強制的に停止するメソッドを削除することが決定されました。今私たちにできることは、特定のフラグ (isInterrupted) を設定し、スレッド コードが正しく記述され、このフラグが処理されることを祈ることだけです。このフラグ「それは、『糸、止めてください。とても重要です!』という標識のようなものです。しかし、糸が止まるかどうかは別問題です。」

「しかし、InterruptedException はどうなるのでしょうか?」

「このスレッドで実行されているコードに大量の try-catch ブロックがある場合はどうなるでしょうか? たとえどこかで InterruptedException が発生したとしても、try-catch がそれをキャッチせずに忘れてしまうという保証はまったくありません。したがって、スレッドが停止します。」

「もう 1 つのことは、スレッドはすでにかなり低レベルのプログラミングであると考えられているということです。しかし、それについては次回お話しします。」

「あなたはエリーじゃない、シェヘラザードだ!」

「それで、アミーゴ! 今回のレッスンの内容はすべて分かりましたか?」

「はい。」

「わかった、いいよ」