次のコードを使用すると例外がIllegalThreadStateException
発生します:このスレッドを(を使用してthread.start()
)一度開始し、別の場所で再度開始しようとしたため、次のコードを使用しました:
thread.interrupt();
thread.start();
しかしthread.start()
、投げてIllegalThreadStateException
います。
それを解決するには何を使うべきですか?
次のコードを使用すると例外がIllegalThreadStateException
発生します:このスレッドを(を使用してthread.start()
)一度開始し、別の場所で再度開始しようとしたため、次のコードを使用しました:
thread.interrupt();
thread.start();
しかしthread.start()
、投げてIllegalThreadStateException
います。
それを解決するには何を使うべきですか?
Thread
オブジェクトは1回だけ開始することを目的としています。を停止/中断する必要がありThread
、それを再開したい場合は、新しいインスタンスを作成して、それを呼び出す必要がありますstart()
。
thread.interrupt(); // if you need to make sure thread's run() method stops ASAP
thread = new MyThreadSubclass();
thread.start();
IllegalThreadStateException-スレッドがすでに開始されている場合。
start()
以前に電話をかけたとしても、もう一度電話をかけられないことは100%明確ではありませんがinterrupt()
、それが機能する方法です。
標準JavaのAPIドキュメントを見ると、この問題はより明確です。
ネイトの答えに加えて。
AnkitRox はコメントで次のように述べています。
ありがとうネイト。私もあなたの方法を試していました。しかし、そのときに発生した問題は、新しいインスタンスの新しいスレッドを開始し、前のスレッドも機能していたことです。
つまり、問題は「割り込みを呼び出してもスレッドがまだ実行されている」ことのようです。次のサンプルを検討してください (見苦しいですが、主なアイデアを示すには十分です):
final Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
for (int i = 0; i < 100000000; i++); // simulate some action
System.out.println("hi, interrupted = "
+ Thread.currentThread().isInterrupted());
}
}
});
t.start();
new Timer(true).schedule(
new TimerTask() {
public void run() {
t.interrupt();
}
},
1000 // 1 second delay
);
interrupt()
が呼び出された後も、スレッドは引き続き実行されることに注意してください。生成される出力は次のとおりです。
hi, interrupted = false
hi, interrupted = true
hi, interrupted = true
hi, interrupted = true
...
hi, interrupted = true
実際には、強制的に閉じない限り、プログラムは停止しません。それで、 は何をinterrupt()
しますか?中断フラグを に設定するだけtrue
です。interrupt()
が呼び出された後、Thread.currentThread().isInterrupted()
が戻り始めfalse
ます。それだけです。
別のケースとしてinterrupt()
、 をスローするメソッドのいずれかの呼び出しでスレッドがブロックされている間に が呼び出された場合、そのメソッドは をスローしInterruptedException
て戻りInterruptedException
ます。そして、スレッドのコードがその例外を「食べる」だけの場合、スレッドは引き続き実行されます。サンプルを検討してください。
final Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
System.out.println("hi, interrupted = "
+ Thread.currentThread().isInterrupted());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("got InterruptedException");
}
}
}
});
t.start();
new Timer(true).schedule(
new TimerTask() {
public void run() {
t.interrupt();
}
},
1000 // 1 second delay
);
interrupt()
が呼び出された後も、スレッドは引き続き実行されることに注意してください。生成される出力は次のとおりです。
hi, interrupted = false
got InterruptedException
hi, interrupted = false
hi, interrupted = false
...
hi, interrupted = false
今回は が呼び出されたinterrupted = false
後でも注意してください。interrupt()
これは、InterruptedException
がキャッチされるたびに、中断フラグが にリセットされるためfalse
です。
Java では、スレッドの停止は協調メカニズムです。つまり、スレッド自体の協力なしにはできないということです。上記のサンプルの修正版は次のとおりです。
final Thread t = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hi, interrupted = "
+ Thread.currentThread().isInterrupted());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("we've been interrupted");
// restore the interrupted flag
Thread.currentThread().interrupt();
}
}
}
});
t.start();
new Timer(true).schedule(
new TimerTask() {
public void run() {
t.interrupt();
}
},
1000 // 1 second delay
);
したがって、正しいアプローチは、中断されたフラグを定期的にチェックすることです。中断されたステータスが検出された場合は、できるだけ早く戻ります。別の一般的なオプションは、まったく使用Thread.interrupt()
しないことですが、代わりにいくつかのカスタムブール値を使用します。