Wie tötest du einen java.lang.Thread
in Java?
ExecutorStatus
auf diese Frage: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Wie tötest du einen java.lang.Thread
in Java?
ExecutorStatus
auf diese Frage: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Antworten:
In diesem Thread von Sun erfahren Sie, warum sie veraltet sindThread.stop()
. Es wird detailliert beschrieben, warum dies eine schlechte Methode war und was getan werden sollte, um Threads im Allgemeinen sicher zu stoppen.
Sie empfehlen, eine gemeinsam genutzte Variable als Flag zu verwenden, die den Hintergrundthread zum Stoppen auffordert. Diese Variable kann dann von einem anderen Objekt festgelegt werden, das die Beendigung des Threads anfordert.
getConnection()
von java.sql.DriverManager
. Wenn der Verbindungsversuch zu lange dauert, versuche ich, den entsprechenden Thread durch Aufrufen zu beenden, Thread.interrupt()
aber er beeinflusst den Thread überhaupt nicht. Das Thread.stop()
funktioniert jedoch, obwohl Orakel sagt, dass es nicht funktionieren sollte, wenn interrupt()
nicht. Ich frage mich, wie es funktioniert und vermeide es, veraltete Methoden zu verwenden.
Im Allgemeinen tun Sie nicht ..
Sie bitten es, alles, was es tut, mit Thread.interrupt () zu unterbrechen (Javadoc-Link)
Eine gute Erklärung, warum hier im Javadoc (Java Technote Link)
interrupt()
Methode aufgerufen wird? Die Hauptfrage bezieht sich auf die Protokollgenerierung für jeden neuen Thread.
In Java werden Threads nicht getötet, aber das Stoppen eines Threads erfolgt auf kooperative Weise . Der Thread wird zum Beenden aufgefordert und der Thread kann dann ordnungsgemäß heruntergefahren werden.
Oft wird ein volatile boolean
Feld verwendet, das der Thread regelmäßig überprüft und beendet, wenn er auf den entsprechenden Wert gesetzt wird.
Ich würde a nicht verwenden boolean
, um zu überprüfen, ob der Thread beendet werden soll . Wenn Sie volatile
als Feldmodifikator verwenden, funktioniert dies zuverlässig. Wenn Ihr Code jedoch komplexer wird und stattdessen andere Blockierungsmethoden innerhalb der while
Schleife verwendet, kann es vorkommen, dass Ihr Code überhaupt nicht beendet wird oder zumindest länger dauert als Sie könnte wollen.
Bestimmte blockierende Bibliotheksmethoden unterstützen die Unterbrechung.
Jeder Thread hat bereits einen Status eines unterbrochenen Booleschen Flags, den Sie verwenden sollten. Es kann folgendermaßen implementiert werden:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Quellcode aus Java Concurrency in der Praxis angepasst . Da die cancel()
Methode öffentlich ist, können Sie einen anderen Thread diese Methode wie gewünscht aufrufen lassen.
Eine Möglichkeit besteht darin, eine Klassenvariable festzulegen und als Sentinel zu verwenden.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Setzen Sie eine externe Klassenvariable, dh flag = true im obigen Beispiel. Setzen Sie es auf false, um den Thread zu "töten".
volatile
um sicherzustellen, dass es überall richtig funktioniert. Die innere Klasse ist nicht statisch, daher sollte das Flag eine Instanzvariable sein. Das Flag sollte in einer Accessor-Methode gelöscht werden, damit andere Operationen (wie Interrupt) ausgeführt werden können. Der Name "flag" ist nicht beschreibend.
Es gibt eine Möglichkeit, wie Sie es tun können. Aber wenn Sie es verwenden mussten, sind Sie entweder ein schlechter Programmierer oder Sie verwenden einen Code, der von schlechten Programmierern geschrieben wurde. Sie sollten also darüber nachdenken, nicht mehr ein schlechter Programmierer zu sein oder diesen schlechten Code nicht mehr zu verwenden. Diese Lösung ist nur für Situationen geeignet, in denen es keinen anderen Weg gibt.
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
selbst wenn sie veraltet ist.
Thread.stop
macht dasselbe, überprüft aber auch den Zugriff und die Berechtigungen. Die Verwendung Thread.stop
ist ziemlich offensichtlich, und ich erinnere mich nicht an den Grund, warum ich Thread.stop0
stattdessen verwendet habe. Vielleicht Thread.stop
hat es für meinen Sonderfall nicht funktioniert (Weblogic auf Java 6). Oder vielleicht, weil Thread.stop
es veraltet ist und Warnung verursacht.
Ich möchte einige Beobachtungen hinzufügen, die auf den gesammelten Kommentaren basieren.
Thread.stop()
stoppt einen Thread, wenn der Sicherheitsmanager dies zulässt.Thread.stop()
ist gefährlich. Wenn Sie jedoch in einer JEE-Umgebung arbeiten und keine Kontrolle über den aufgerufenen Code haben, kann dies erforderlich sein. Siehe Warum ist Thread.stop veraltet?stop()
erzeugt einen neuen ThreadDeathError
Fehler auf dem Aufruf - Thread und dann diese Fehler auf das wirft Zielgewinde. Daher ist die Stapelverfolgung im Allgemeinen wertlos.stop()
Überprüft in JRE 6 den Sicherheitsmanager und ruft stop1()
diese Anrufe dann auf stop0()
. stop0()
ist nativer Code.Thread.stop()
wurde (noch) nicht entfernt, aber Thread.stop(Throwable)
in Java 11 entfernt. ( Mailingliste , JDK-8204243 )Ich würde dafür stimmen Thread.stop()
.
Zum Beispiel haben Sie einen lang anhaltenden Betrieb (wie eine Netzwerkanforderung). Angeblich warten Sie auf eine Antwort, aber es kann einige Zeit dauern, bis der Benutzer zu einer anderen Benutzeroberfläche navigiert. Dieser wartende Thread ist jetzt a) nutzlos b) potenzielles Problem, da er, wenn er ein Ergebnis erhält, völlig nutzlos ist und Rückrufe auslöst, die zu einer Reihe von Fehlern führen können.
All dies und er kann eine Antwortverarbeitung durchführen, die CPU-intensiv sein kann. Und Sie als Entwickler können es nicht einmal stoppen, weil Sie nicht den if (Thread.currentThread().isInterrupted())
gesamten Code mit Zeilen versehen können.
Die Unfähigkeit, einen Thread gewaltsam zu stoppen, ist also seltsam.
Thread.stop()
trotzdem nicht sicher anrufen . Sie stimmen nicht ab Thread.stop()
, Sie fragen nach jeder Person, die jede Operation durchführt, die möglicherweise lange dauert, um sie sicher abzubrechen. Und das mag eine gute Idee sein, hat aber nichts mit der Implementierung zu tun Thread.stop()
, um die sichere Abtreibung zu beantragen. Dafür haben wir schon interrupt
.
stop
.
Die Frage ist eher vage. Wenn Sie gemeint haben: "Wie schreibe ich ein Programm, damit ein Thread nicht mehr ausgeführt wird, wenn ich es möchte?", Sollten verschiedene andere Antworten hilfreich sein. Aber wenn Sie meinten "Ich habe einen Notfall mit einem Server, den ich momentan nicht neu starten kann, und ich brauche nur einen bestimmten Thread, um zu sterben, was auch immer", dann brauchen Sie ein Interventionstool, das mit Überwachungstools wie z jstack
.
Zu diesem Zweck habe ich jkillthread erstellt . Siehe die Gebrauchsanweisung.
Es gibt natürlich den Fall, dass Sie einen nicht vollständig vertrauenswürdigen Code ausführen. (Ich persönlich habe dies dadurch erreicht, dass hochgeladene Skripte in meiner Java-Umgebung ausgeführt werden können. Ja, überall klingelt die Sicherheitsalarmglocke, aber dies ist Teil der Anwendung.) In diesem unglücklichen Fall sind Sie zunächst nur hoffnungsvoll, wenn Sie Skriptschreiber fragen eine Art boolesches Run / Don't-Run-Signal zu respektieren. Ihre einzige anständige Ausfallsicherheit besteht darin, die Stoppmethode für den Thread aufzurufen, wenn sie beispielsweise länger als eine Zeitüberschreitung ausgeführt wird.
Dies ist jedoch nur "anständig" und nicht absolut, da der Code den ThreadDeath-Fehler (oder eine andere Ausnahme, die Sie explizit auslösen) abfangen und ihn nicht erneut auslösen kann, wie es ein Gentleman-Thread tun soll. Das Endergebnis ist also AFAIA, es gibt keine absolute Ausfallsicherheit.
Es gibt keine Möglichkeit, einen Thread ordnungsgemäß zu beenden.
Sie können versuchen, den Thread zu unterbrechen. Eine übliche Strategie besteht darin, eine Giftpille zu verwenden, um dem Thread eine Nachricht zu senden, dass er sich selbst stoppen soll
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”);
Im Allgemeinen beenden, stoppen oder unterbrechen Sie einen Thread nicht (oder überprüfen, ob er unterbrochen ist ()), sondern lassen ihn auf natürliche Weise beenden.
Es ist einfach. Sie können eine beliebige Schleife zusammen mit einer (flüchtigen) booleschen Variablen in der run () -Methode verwenden, um die Aktivität des Threads zu steuern. Sie können auch vom aktiven Thread zum Haupt-Thread zurückkehren, um ihn zu stoppen.
Auf diese Weise tötest du anmutig einen Thread :).
Versuche einer abrupten Thread-Beendigung sind bekannte schlechte Programmierpraktiken und Hinweise auf ein schlechtes Anwendungsdesign. Alle Threads in der Multithread-Anwendung haben explizit und implizit denselben Prozessstatus und müssen zusammenarbeiten, um die Konsistenz zu gewährleisten. Andernfalls ist Ihre Anwendung anfällig für Fehler, die sehr schwer zu diagnostizieren sind. Es liegt daher in der Verantwortung des Entwicklers, diese Konsistenz durch sorgfältiges und klares Anwendungsdesign sicherzustellen.
Es gibt zwei richtige Hauptlösungen für die gesteuerten Thread-Abschlüsse:
Eine gute und detaillierte Erläuterung der Probleme im Zusammenhang mit der abrupten Thread-Beendigung sowie Beispiele für falsche und richtige Lösungen für die kontrollierte Thread-Beendigung finden Sie hier:
Hier sind ein paar gute Lektüren zu diesem Thema:
Ich habe den Interrupt nicht in Android zum Laufen gebracht, also habe ich diese Methode verwendet, funktioniert perfekt:
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;
}
"Einen Thread töten" ist nicht der richtige Ausdruck. Hier ist eine Möglichkeit, wie wir das ordnungsgemäße Beenden / Beenden des Threads auf Willen implementieren können:
Runnable, das ich verwendet habe:
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;
}
}
Die auslösende Klasse:
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 ist veraltet. Wie stoppen wir einen Thread in Java?
Verwenden Sie immer die Interrupt-Methode und die Zukunft, um eine Stornierung anzufordern
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);
}
}
};
}
}