wake-up-neo.net

Wie kann ich einen Thread in Java starten/stoppen/neu starten?

Es fällt mir schwer, einen Weg zu finden, einen Thread in Java zu starten, zu stoppen und neu zu starten.

Insbesondere habe ich eine Klasse Task (derzeit implementiert Runnable) in einer Datei Task.Java. Meine Hauptanwendung muss in der Lage sein, diese Aufgabe mit einem Thread zu starten, den Thread zu stoppen (zu beenden), wenn er muss, und manchmal den Thread zu töten und neu zu starten ...

Mein erster Versuch war mit ExecutorService, aber ich finde keinen Weg, eine Aufgabe neu zu starten. Wenn ich .shutdownnow() verwende, schlägt ein zukünftiger Aufruf von .execute() fehl, da die ExecutorService "heruntergefahren" ist ...

Wie konnte ich das erreichen?

47
Shaitan00

Sobald ein Thread beendet ist, können Sie ihn nicht erneut starten. Es hält jedoch nichts dagegen, einen neuen Thread zu erstellen und zu starten.

Option 1: Erstellen Sie einen neuen Thread, anstatt einen Neustart zu versuchen.

Option 2: Anstatt den Thread anhalten zu lassen, warten Sie, und wenn er eine Benachrichtigung erhält, können Sie zulassen, dass er wieder funktioniert. Auf diese Weise wird der Thread niemals angehalten und muss nie neu gestartet werden.

Bearbeiten basierend auf Kommentar:

Um den Thread zu "töten", können Sie Folgendes tun.

yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
41
Taylor Leese

Es ist nicht möglich, einen Thread zu beenden, es sei denn, der in diesem Thread ausgeführte Code prüft und erlaubt die Beendigung.

Sie sagten: "Leider muss ich es beenden/neu starten ... Ich habe keine vollständige Kontrolle über den Inhalt des Threads und für meine Situation ist ein Neustart erforderlich."

Wenn der Inhalt des Threads die Beendigung seiner Ausführung nicht zulässt, können Sie diesen Thread nicht beenden.

In Ihrem Beitrag haben Sie gesagt: "Mein erster Versuch war mit ExecutorService, aber ich finde keinen Weg, eine Aufgabe neu zu starten. Wenn ich .shutdownnow () benutze ..."

Wenn Sie sich die Quelle von "shutdownnow" ansehen, läuft es einfach durch und unterbricht die aktuell laufenden Threads. Dadurch wird ihre Ausführung nicht angehalten, es sei denn, der Code in diesen Threads prüft, ob er unterbrochen wurde, und stoppt die Ausführung selbst. Also macht shutdownnow wahrscheinlich nicht das, was Sie denken.

Lassen Sie mich erläutern, was ich meine, wenn ich sage, dass der Inhalt des Threads es zulassen muss, dass der Thread beendet wird:

myExecutor.execute(new Runnable() {
 public void run() {
  while (true) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

Dieser Thread wird für immer weiter ausgeführt, auch wenn shutdownnow aufgerufen wurde, da er niemals prüft, ob er beendet wurde oder nicht. Dieser Thread wird jedoch geschlossen:

myExecutor.execute(new Runnable() {
 public void run() {
  while (!Thread.interrupted()) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

Da prüft dieser Thread, ob er unterbrochen wurde/heruntergefahren/beendet wurde.

Wenn Sie also einen Thread wollen, der heruntergefahren werden kann, müssen Sie sicherstellen, dass der Thread überprüft, ob er unterbrochen wurde. Wenn Sie einen Thread wünschen, der "heruntergefahren" und "neu gestartet" werden kann, können Sie ein lauffähiges Programm erstellen, das neue Aufgaben übernehmen kann, wie bereits erwähnt.

Warum können Sie einen laufenden Thread nicht herunterfahren? Ich habe tatsächlich gelogen. Sie können "yourThread.stop ()" nennen, aber warum ist das eine schlechte Idee? Der Thread könnte sich in einem synchronisierten Abschnitt (oder einem anderen kritischen Abschnitt befinden), wir beschränken uns jedoch auf die Einstellungen, die durch das synchronisierte Schlüsselwort (hier "geschütztes Schlüsselwort") geschützt werden, wenn Sie ihn stoppen. Synchronisationsblöcke sollen in ihrer Gesamtheit und nur von einem Thread ausgeführt werden, bevor ein anderer Thread darauf zugreift. Wenn Sie einen Thread in der Mitte eines Synchronisationsblocks stoppen, wird der durch den Synchronisierungsblock eingerichtete Schutz ungültig und Ihr Programm wird in einen unbekannten Zustand versetzt. Entwickler machen Sachen in Synchronisierungsblöcken, um die Dinge synchron zu halten. Wenn Sie threadInstance.stop () verwenden, zerstören Sie die Bedeutung von synchronize, was der Entwickler dieses Codes zu erreichen versucht hat und wie der Entwickler dieses Codes seine synchronisierten Blöcke erwartet sich verhalten.

9

Review Java.lang.Thread .

Zum Starten oder Neustarten (nach dem Stoppen eines Threads können Sie denselben Thread nicht erneut starten, es spielt jedoch keine Rolle; erstellen Sie einfach eine neue Thread-Instanz):

// Create your Runnable instance
Task task = new Task(...);

// Start a thread and run your Runnable
Thread t = new Thread(task);

Um dies zu stoppen, müssen Sie eine Methode in Ihrer Task-Instanz haben, die ein Flag setzt, um die run-Methode zu beenden; Rückkehr von run beendet den Thread. Wenn Ihr aufrufender Code wissen muss, dass der Thread wirklich angehalten wurde, bevor er zurückgegeben wird, können Sie join verwenden:

// Tell Task to stop
task.setStopFlag(true);

// Wait for it to do so
t.join();

Zum Neustart: Auch wenn eine Thread nicht neu gestartet werden kann, können Sie Ihre Runnable-Instanz mit einem neuen Thread wiederverwenden, wenn sie einen Status hat und solche, die Sie behalten möchten. das ist das Gleiche. Stellen Sie einfach sicher, dass Ihre Runnable so ausgelegt ist, dass sie mehrere Aufrufe von run zulässt.

8
T.J. Crowder

Sie können einen Thread nicht neu starten. Die beste Option besteht darin, den aktuellen Status des Objekts zu dem Zeitpunkt zu speichern, zu dem der Thread angehalten wurde. Wenn das Objekt mit Vorgängen fortgesetzt werden muss, können Sie das Objekt mithilfe des gespeicherten Objekts neu erstellen und den neuen Thread starten .

Diese beiden Artikel Swing Worker und Concurrency können Ihnen dabei helfen, die beste Lösung für Ihr Problem zu finden.

4
ChadNC

Wie von Taylor L festgestellt, können Sie einen Thread nicht einfach "stoppen" (durch Aufrufen einer einfachen Methode), da Ihr System möglicherweise in einem instabilen Zustand verbleibt, da der externe aufrufende Thread möglicherweise nicht weiß, was in ihm vorgeht dein Faden.

Wenn dies gesagt ist, ist der beste Weg zum "Anhalten" eines Threads, den Thread auf sich aufmerksam zu machen und ihn wissen zu lassen, wann er aufhören soll.

2
JasCav
You can start a thread like:

    Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //Do you task
                    }catch (Exception ex){
                        ex.printStackTrace();}
                }
            });
thread.start();

To stop a Thread:

   thread.join();//it will kill you thread

   //if you want to know whether your thread is alive or dead you can use
System.out.println("Thread is "+thread.isAlive());

Es ist ratsam, einen neuen Thread zu erstellen, anstatt ihn neu zu starten.

0
Sukirti Dash

Es gibt einen Unterschied zwischen dem Anhalten eines Threads und dem Anhalten/Töten. Wenn das Anhalten für Sie bedeutet, den Thread zu beenden, bedeutet ein Neustart einfach, einen neuen Thread zu erstellen und zu starten.

Es gibt Methoden, um Threads aus einem anderen Thread (z. B. Ihrem Spawner) abzutöten, aber im Allgemeinen sind sie unsicher. Es ist möglicherweise sicherer, wenn Ihr Thread ständig ein Flag überprüft, um zu sehen, ob er fortgesetzt werden soll (ich nehme an, dass in Ihrem Thread eine Schleife vorhanden ist) und der externe "Controller" den Status dieses Flag ändern soll. 

Sie können ein wenig mehr in sehen: http://Java.Sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

Darf ich fragen, warum Sie den Thread beenden und neu starten möchten? Warum nicht einfach warten, bis die Dienste wieder benötigt werden? Java verfügt genau zu diesem Zweck über Synchronisationsmechanismen. Der Thread befindet sich im Ruhezustand, bis der Controller ihn mitteilt, um die Ausführung fortzusetzen.

0
Uri

Wenn Ihre Aufgabe eine Art Aktion in einer Schleife ausführt, gibt es eine Möglichkeit, die Verarbeitung anzuhalten/neu zu starten, aber ich denke, dass dies außerhalb des aktuellen Threads-APIs liegen muss. Wenn es sich um einen Single-Shot-Prozess handelt, kenne ich keine Möglichkeit zum Suspendieren/Neustarten, ohne in eine API zu laufen, die veraltet ist oder nicht mehr zulässig ist.

Bei Schleifenprozessen könnte ich mir am leichtesten vorstellen, dass der Code, der die Task erzeugt, einen ReentrantLock instanziiert und an die Task weiterleitet sowie eine Referenz selbst speichert. Jedes Mal, wenn die Task in die Schleife eintritt, versucht sie, die ReentrantLock-Instanz zu sperren. Wenn die Schleife abgeschlossen ist, sollte sie entsperrt werden. Möglicherweise möchten Sie alle try/finally kapseln und sicherstellen, dass Sie die Sperre am Ende der Schleife loslassen, auch wenn eine Ausnahme ausgelöst wird.

Wenn Sie die Aufgabe anhalten möchten, versuchen Sie einfach, den Hauptcode zu sperren (da Sie eine Referenz zur Hand haben). Was dies tun wird, ist zu warten, bis die Schleife abgeschlossen ist und keine weitere Iteration beginnen darf (da der Haupt-Thread eine Sperre hält). Um den Thread neu zu starten, müssen Sie ihn einfach über den Hauptcode entsperren. Dadurch kann die Task ihre Schleifen fortsetzen.

Um den Thread dauerhaft zu stoppen, würde ich die normale API verwenden oder ein Flag in der Task und einen Setter für das Flag (so etwas wie stopImmediately) belassen. Wenn die Schleife auf einen echten Wert für dieses Flag stößt, wird die Verarbeitung beendet und die Ausführungsmethode abgeschlossen.

0
Gennadiy