java.lang.Thread
Javaでどうやって殺すの?
ExecutorStatus
はこの質問に関する答えを好む:stackoverflow.com/questions/2275443/how-to-timeout-a-thread
java.lang.Thread
Javaでどうやって殺すの?
ExecutorStatus
はこの質問に関する答えを好む:stackoverflow.com/questions/2275443/how-to-timeout-a-thread
回答:
彼らが非推奨になった理由について、SunによるThread.stop()
このスレッドを参照してください。これがなぜ悪い方法であったのか、そして一般的にスレッドを安全に停止するために何をすべきかについて詳しく説明します。
彼らが推奨する方法は、バックグラウンドスレッドに停止を要求するフラグとして共有変数を使用することです。この変数は、スレッドの終了を要求する別のオブジェクトによって設定できます。
getConnection()
からのメソッドを使用しjava.sql.DriverManager
ます。接続の試行に時間がかかりすぎる場合は、呼び出しによって対応するスレッドを強制終了しようとしますThread.interrupt()
が、スレッドにはまったく影響しません。Thread.stop()
Oracleがあれば、それは動作してはならないと言うが、しかし働きinterrupt()
ません。私はそれをどのように機能させ、非推奨のメソッドの使用を避けるのかと思います。
Javaでは、スレッドは強制終了されませんが、スレッドの停止は協調的に行われます。スレッドは終了するように求められ、スレッドは正常にシャットダウンできます。
多くの場合volatile boolean
、対応する値に設定されるとスレッドが定期的にチェックして終了するフィールドが使用されます。
私はしません使用してboolean
スレッドがすべきかどうかを確認するために終了します。volatile
フィールド修飾子として使用する場合、これは確実に機能しますが、コードがより複雑になると、代わりにwhile
ループ内で他のブロッキングメソッドを使用するため、コードがまったく終了しないか、少なくとも、コードが長くなる可能性があります。したいかもしれません。
特定のブロッキングライブラリメソッドは割り込みをサポートしています。
すべてのスレッドにはすでにブールフラグの割り込みステータスがあり、それを利用する必要があります。次のように実装できます。
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Java Concurrency in Practiceから採用されたソースコード。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です。スレッドを「強制終了」するにはfalseに設定します。
volatile
どこでも正しく機能するように「フラグ」を作成します。内部クラスは静的ではないため、フラグはインスタンス変数である必要があります。他の操作(割り込みなど)を実行できるように、フラグはアクセサメソッドでクリアする必要があります。「フラグ」という名前は説明的ではありません。
それを行う方法はあります。しかし、それを使用しなければならなかった場合、あなたは悪いプログラマーであるか、悪いプログラマーによって書かれたコードを使用しています。したがって、悪いプログラマーになるのをやめるか、この悪いコードの使用をやめることを考えるべきです。この解決策は、他に方法がない場合のみです。
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
非推奨になったとしてもパブリックを呼び出すことができるため、これを行う理由はまったくありません。
Thread.stop
は同じことを行いますが、アクセスと権限もチェックします。使用することThread.stop
はかなり明白でありThread.stop0
、その代わりに使用した理由を覚えていません。たぶんThread.stop
私の特別なケース(Java 6上のWeblogic)ではうまくいかなかったかもしれません。または、Thread.stop
が非推奨であり、警告が表示されるためです。
蓄積されたコメントに基づいて、いくつかの観察を追加したいと思います。
Thread.stop()
セキュリティーマネージャーが許可する場合、スレッドを停止します。Thread.stop()
危険です。そうは言っても、JEE環境で作業していて、呼び出されるコードを制御できない場合は、必要になる可能性があります。Thread.stopが廃止された理由を参照してください。stop()
呼び出しスレッドに新しいThreadDeathError
エラーを作成し、そのエラーをターゲットスレッドにスローします。したがって、スタックトレースは一般的に価値がありません。stop()
、セキュリティマネージャーに確認し、それを呼び出しstop1()
ますstop0()
。stop0()
ネイティブコードです。Thread.stop()
は(まだ)削除されていませんがThread.stop(Throwable)
、Java 11で削除されました(メーリングリスト、JDK-8204243)に投票しThread.stop()
ます。
たとえば、ネットワークリクエストのように長時間続くオペレーションがあるとします。おそらくあなたは応答を待っていますが、時間がかかり、ユーザーが他のUIに移動する可能性があります。この待機中のスレッドは現在、a)役に立たないb)潜在的な問題です。彼が結果を得るとき、それは完全に役に立たず、エラーの数につながるコールバックをトリガーするからです。
これらすべてと、CPUに負荷がかかる可能性のある応答処理を実行できます。またif (Thread.currentThread().isInterrupted())
、すべてのコードで行をスローすることはできないため、開発者はそれを止めることもできません。
したがって、奇妙なスレッドを強制的に停止することができません。
Thread.stop()
とにかく安全に呼び出すことができません。に投票するのではなくThread.stop()
、安全に中止できるようになるまでに時間がかかる可能性のあるすべての操作を実装するすべての人を求めています。そしてそれは良い考えかもしれませんがThread.stop()
、安全な中絶を要求する方法として実装することとは何の関係もありません。私たちはすでにinterrupt
そのために持っています。
stop
。
質問はかなりあいまいです。「必要なときにスレッドが実行を停止するようにプログラムを作成する方法」を意味している場合は、他のさまざまな応答が役立つはずです。しかし、「サーバーに緊急事態が発生したため、現在再起動できず、特定のスレッドが必要な場合にのみ、死ぬ可能性があります」という場合、のような監視ツールと一致する介入ツールが必要です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”);
通常、スレッドを強制終了、停止、または中断することはせず(または、interrupted()であるかどうかを確認します)、自然に終了させます。
簡単です。ループをrun()メソッド内で(揮発性)ブール変数と一緒に使用して、スレッドのアクティビティを制御できます。アクティブスレッドからメインスレッドに戻って停止することもできます。
このようにして、スレッドを優雅に削除します:)。
突然のスレッド終了の試みは、よく知られた悪いプログラミング慣行であり、アプリケーション設計が不十分であることの証拠です。マルチスレッドアプリケーションのすべてのスレッドは、明示的および暗黙的に同じプロセス状態を共有し、一貫性を保つために相互に協力することを強制されます。したがって、慎重かつ明確なアプリケーション設計を通じてそのような一貫性の保証を提供することは、開発者の責任です。
制御されたスレッドの終了には、主に2つの正しい解決策があります。
突然のスレッドの終了に関連する問題の適切で詳細な説明と、制御されたスレッドの終了の間違った正しい解決策の例は、次の場所にあります。
私は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;
}
「スレッドを強制終了する」は適切なフレーズではありません。これは、スレッドの正常な完了/終了を自由に実装できる1つの方法です。
私が使用したRunnable:
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");
}
}
Thread.stopは非推奨です。Javaでスレッドを停止するにはどうすればよいですか?
常に割り込みメソッドとフューチャーを使用してキャンセルをリクエストする
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}