JavaでどうやってJava.lang.Thread
を殺すのですか?
これを参照してください なぜThread.stop()
を非推奨にしたのかについてのSunのスレッド 。なぜこれが悪い方法であるのか、そして一般的に安全にスレッドを停止するために何をすべきかについて詳しく説明します。
彼らが推奨する方法は、バックグラウンドスレッドに停止を要求するフラグとして共有変数を使用することです。この変数は、スレッドの終了を要求する別のオブジェクトによって設定できます。
一般的には違います。
Thread.interrupt()(javadoc link) を使用して、何をしていても中断してください。
Javadocにある理由の良い説明 ここ(Java technote link)
Javaでは、スレッドは強制終了されませんが、スレッドの停止は協力的な方法で行われます。スレッドは終了するように要求され、スレッドは正常にシャットダウンできます。
多くの場合、volatile boolean
フィールドが使用されます。このフィールドは、対応する値に設定されると、スレッドが定期的にチェックして終了します。
Inot notboolean
を使用して、スレッドが終了する必要があるかどうかを確認しますterminate。 volatile
をフィールド修飾子として使用すると、これは信頼性の高い動作をしますが、コードがより複雑になると、代わりにwhile
ループ内で他のブロックメソッドを使用するため、コードが終了しないまたは少なくともは長くなります。
特定のブロッキングライブラリメソッドは割り込みをサポートします。
すべてのスレッドには既にブールフラグ割り込みステータスがあり、それを利用する必要があります。次のように実装できます。
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Java同時実行性 から適応したソースコード。 cancel()
メソッドはパブリックなので、別のスレッドに必要に応じてこのメソッドを呼び出させることができます。
1つの方法は、クラス変数を設定してそれをセンチネルとして使用することです。
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
外部クラス変数、すなわち上記の例ではflag = trueを設定します。スレッドを「kill」するにはfalseに設定します。
あなたがそれを行うことができる方法があります。しかし、もしあなたがそれを使わなければならないのなら、あなたは悪いプログラマーであるか、あなたは悪いプログラマーによって書かれたコードを使っています。だから、あなたは悪いプログラマーであることをやめるか、この悪いコードを使うのをやめることを考えるべきです。この解決策は、THERE IS NO OTHER WAYの場合のみです。
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
集めたコメントに基づいて、いくつかの所見を追加したいと思います。
私はThread.stop()
に投票したいと思います。
例えば、あなたは(ネットワーク要求のような)長続きする操作をしています。おそらくあなたは応答を待っていますが、それは時間がかかり、ユーザが他のUIに移動した可能性があります。この待機スレッドは、a)無用なb)潜在的な問題です。なぜなら、彼が結果を得るとき、それは完全に無用であり、彼が多くのエラーを引き起こす可能性があるコールバックを引き起こすでしょう。
それだけでなく、彼は応答処理を行うことができます。そしてあなたは、開発者として、それを止めることすらできません。なぜなら、すべてのコードにif (Thread.currentThread().isInterrupted())
行を入れることはできないからです。
そのため、スレッドを強制的に停止させることができないのは奇妙なことです。
質問はかなりあいまいです。 「必要に応じてスレッドが実行を停止するようにプログラムを作成する方法」と言った場合は、他のさまざまな応答が役立つはずです。しかし、「今すぐ再起動できないサーバーで緊急事態が発生したため、特定のスレッドを使用するだけで解決できる場合がある」という意味であれば、jstack
のような監視ツールと一致する介入ツールが必要です。
このために jkillthread を作成しました。使用方法についてはその説明を参照してください。
もちろん、完全に信頼されていないコードを実行している場合もあります。 (私は個人的にはアップロードしたスクリプトを私のJava環境で実行することを許可しています。はい、いたるところにセキュリティアラームのベルが鳴っていますが、それはアプリケーションの一部です。)ある種のブーリアンラン/ドントラン信号を尊重するため。あなたの唯一のまともなフェイルセーフは、例えば、それがあるタイムアウトより長く実行されるなら、スレッドでstopメソッドを呼び出すことです。
しかし、これは単なる "まともな"ものであり、絶対的なものではありません。コードがThreadDeathエラー(または明示的にスローした例外)をキャッチし、紳士的なスレッドのように再スローしないためです。つまり、最終的な結果はAFAIAです。絶対的なフェイルセーフはありません。
スレッドを正常に終了させる方法はありません。
あなたはスレッドを中断しようとすることができます、1コモンズ戦略はそれ自身を停止するようにスレッドにメッセージを送るために毒薬を使うことです
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
一般的には、スレッドを殺したり、停止したり、中断したり(または中断された()したかどうかを確認したり)しませんが、自然に終了させてください。
簡単です。スレッドのアクティビティを制御するために、run()メソッド内で(揮発性の)ブール変数と一緒に任意のループを使用できます。アクティブスレッドからメインスレッドに戻って停止することもできます。
このようにしてあなたは優雅にスレッドを殺します:)。
突然のスレッド終了の試みは、よく知られている悪いプログラミング手法であり、アプリケーション設計が良くないことの証拠です。マルチスレッドアプリケーションのすべてのスレッドは、明示的にも暗黙的にも同じプロセス状態を共有し、一貫性を保つために互いに協力することを余儀なくされます。そうしないと、アプリケーションは実際には診断が困難なバグになりがちです。したがって、慎重かつ明確なアプリケーション設計を介してそのような一貫性を保証することは開発者の責任です。
制御スレッドの終了には、主に2つの正しい解決策があります。
突然のスレッド終了に関連する問題の詳細な説明と、制御されたスレッド終了のための間違った正しい解決策の例はここにあります。
「スレッドを殺す」は正しい使い方ではありません。これは私達が意志でスレッドの優雅な完了/終了を実装することができる1つの方法です:
私が使用したランナブル:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
トリガークラス:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
私はAndroidの中で動作するように割り込みを取得できませんでしたので、私はこの方法を使用して、完璧に動作します:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}