Ich brauche eine Lösung, um den Thread in Java richtig zu stoppen.
Ich habe eine IndexProcessor
Klasse, die die Runnable-Schnittstelle implementiert:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
@Override
public void run() {
boolean run = true;
while (run) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
}
Und ich habe eine ServletContextListener
Klasse, die den Thread startet und stoppt:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
@Override
public void contextInitialized(ServletContextEvent event) {
thread = new Thread(new IndexProcessor());
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
thread.interrupt();
LOGGER.debug("Thread successfully stopped.");
}
}
}
Wenn ich Tomcat herunterfahre, wird in meiner IndexProcessor-Klasse die Ausnahme angezeigt:
2012-06-09 17:04:50,671 [Thread-3] ERROR IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
at java.lang.Thread.run(Unknown Source)
Ich benutze JDK 1.6. Die Frage ist also:
Wie kann ich den Thread stoppen und keine Ausnahmen auslösen?
PS Ich möchte keine .stop();
Methode verwenden, da diese veraltet ist.
java
multithreading
listener
Paulius Matulionis
quelle
quelle
InterruptedException
. Das denke ich, aber ich frage mich auch, wie der Standardweg ist.InterruptedException
finden Sie unter ibm.com/developerworks/library/j-jtp05236 .Antworten:
In der
IndexProcessor
Klasse müssen Sie ein Flag setzen, das den Thread darüber informiert, dass er beendet werden muss, ähnlich wie die Variablerun
, die Sie gerade im Klassenbereich verwendet haben.Wenn Sie den Thread stoppen möchten, setzen Sie dieses Flag und rufen auf
join()
den Thread auf und warten, bis er beendet ist.Stellen Sie sicher, dass das Flag threadsicher ist, indem Sie eine flüchtige Variable verwenden oder Getter- und Setter-Methoden verwenden, die mit der als Flag verwendeten Variablen synchronisiert sind.
Dann in
SearchEngineContextListener
:quelle
Die Verwendung
Thread.interrupt()
ist ein durchaus akzeptabler Weg, dies zu tun. In der Tat ist es wahrscheinlich einer Flagge vorzuziehen, wie oben vorgeschlagen. Der Grund dafür ist, dass Sie sich in einem unterbrechbaren Sperranruf befinden (wie zThread.sleep
Sperranruf befinden oder mit java.nio Channel-Vorgängen), tatsächlich sofort aus diesen herausbrechen können.Wenn Sie ein Flag verwenden, müssen Sie warten, bis der Blockierungsvorgang abgeschlossen ist, und dann können Sie Ihr Flag überprüfen. In einigen Fällen müssen Sie dies trotzdem tun, z. B. mit standard
InputStream
/,OutputStream
die nicht unterbrechbar sind.In diesem Fall wird die Unterbrechung der E / A durch einen Thread nicht unterbrochen. Sie können dies jedoch problemlos routinemäßig in Ihrem Code ausführen (und dies sollten Sie an strategischen Punkten tun, an denen Sie sicher anhalten und bereinigen können).
Wie ich bereits sagte, besteht der Hauptvorteil darin,
Thread.interrupt()
dass Sie sofort aus unterbrechbaren Anrufen ausbrechen können, was mit dem Flag-Ansatz nicht möglich ist.quelle
interrupt()
möglicherweise in Ordnung, in vielen anderen Fällen jedoch nicht (z. B. wenn eine Ressource geschlossen werden muss). Wenn jemand die innere Funktionsweise der Schleife ändert, müssen Sie daran denken,interrupt()
auf die boolesche Weise zu wechseln . Ich würde von Anfang an den sicheren Weg gehen und die Flagge benutzen.Einfache Antwort: Sie können einen Thread auf zwei Arten intern stoppen:
Sie können Threads auch EXTERN stoppen:
system.exit
(dies beendet Ihren gesamten Prozess)interrupt()
Methode *kill()
oderstop()
)*: Die Erwartung ist, dass dies einen Thread stoppen soll. Was der Thread in diesem Fall tatsächlich tut, hängt jedoch ganz von dem ab, was der Entwickler beim Erstellen der Thread-Implementierung geschrieben hat.
Ein häufiges Muster, das Sie bei Implementierungen von Ausführungsmethoden sehen, ist a
while(boolean){}
, bei dem der Boolesche Wert normalerweise einen Namen hatisRunning
, eine Mitgliedsvariable seiner Thread-Klasse ist, flüchtig ist und normalerweise von anderen Threads über eine Art Setter-Methode aufgerufen werden kann, zkill() { isRunnable=false; }
. Diese Unterprogramme sind nett, weil sie es dem Thread ermöglichen, alle darin enthaltenen Ressourcen freizugeben, bevor er beendet wird.quelle
Sie sollten Threads immer beenden, indem Sie ein Flag in der
run()
Schleife aktivieren (falls vorhanden).Dein Thread sollte so aussehen:
Dann können Sie den Thread beenden, indem Sie aufrufen
thread.stopExecuting()
. Auf diese Weise wird der Thread sauber beendet, dies dauert jedoch bis zu 15 Sekunden (aufgrund Ihres Schlafes). Sie können thread.interrupt () immer noch aufrufen, wenn es wirklich dringend ist - aber der bevorzugte Weg sollte immer darin bestehen, das Flag zu überprüfen.Um ein Warten von 15 Sekunden zu vermeiden, können Sie den Schlaf folgendermaßen aufteilen:
quelle
Thread
- es implementiertRunnable
- Sie können keineThread
Methoden darauf aufrufen , es sei denn, Sie deklarieren es als ein,Thread
in welchem Fall Sie nicht aufrufen könnenstopExecuting()
In der Regel wird ein Thread beendet, wenn er unterbrochen wird. Warum also nicht den nativen Booleschen Wert verwenden? Versuchen Sie isInterrupted ():
ref- Wie kann ich einen Thread töten? ohne stop () zu verwenden;
quelle
Zum Synchronisieren von Threads bevorzuge ich die Verwendung, mit
CountDownLatch
deren Hilfe Threads warten können, bis der ausgeführte Prozess abgeschlossen ist. In diesem Fall wird die Worker-Klasse mit einerCountDownLatch
Instanz mit einer bestimmten Anzahl eingerichtet. Ein Aufruf derawait
Methode wird blockiert, bis die aktuelle Anzahl aufgrund von Aufrufen dercountDown
Methode Null erreicht ist oder das festgelegte Zeitlimit erreicht ist. Dieser Ansatz ermöglicht das sofortige Unterbrechen eines Threads, ohne auf die angegebene Wartezeit warten zu müssen:Wenn Sie die Ausführung des anderen Threads beenden möchten, führen Sie countDown für den
CountDownLatch
undjoin
den Thread für den Hauptthread aus:quelle
Einige ergänzende Informationen. Sowohl Flag als auch Interrupt werden im Java-Dokument vorgeschlagen.
https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
Verwenden Sie für einen Thread, der lange wartet (z. B. auf Eingaben)
Thread.interrupt
quelle
Ich habe den Interrupt nicht in Android zum Laufen gebracht, also habe ich diese Methode verwendet, funktioniert perfekt:
quelle
volatile
. Siehe docs.oracle.com/javase/specs/jls/se9/html/jls-17.html#jls-17.3 .Irgendwann werde ich es 1000 Mal in meinem onDestroy () / contextDestroyed () versuchen.
quelle