Wie stoppe ich einen Thread richtig?

Status
Nicht offen für weitere Antworten.

JBubble

Mitglied
Hallo zusammen,

ich habe in einer Anwendung einen Thread, der folgendermaßen gestartet wurde:

Code:
Thread t = new Thread(xxx);
t.start();

Bei xxx handelt es sich um ein Objekt, welches eine Schnittstelle implementiert, die direkt von Runnable erbt. So weit so gut. Doch wie stoppe ich einen solchen Thread wieder sauber?

Gemäß http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html kann

Code:
t.stop();

zu inkonsistenten Daten führen. Sie empfehlen daher, in der run()-Methode des Threads permanent eine Variable zu überpüfen, die in der stop()-Methode verändert werden kann. Dies kann dann quasi so aussehen:

Code:
private volatile boolean running = true;
public void stop() {
running = false;
}

public void run() {
while(running) {
...
}
}

Zumindest verstehe ich das Beispiel so ähnlich. Nun gelingt es mir leider nicht, dieses saubere Beenden auf meine Implementierung oben anzuwenden. Wo genau sollte ich denn jetzt diese stop()-Methode implementieren? In der Klasse von xxx (siehe Beispiel oben, ist quasi ein Runnable) macht es ja keinen Sinn, denn ich würde später ja doch wieder die Methode stop() des Objekts t aufrufen - oder doch direkt von xxx, so dass ich quasi sage

Code:
// Thread t stoppen:
xxx.stop();

Würde dies den Thread t sauber beenden, oder gibts da was anderes?

Wenn ich direkt von Thread ableite kann ich stop() nicht überschreiben, da dies eine final-Methode ist.

Bin für jede Anregung und jeden Denkanstoß dankbar,
viele Grüsse
JBubble
 
Die stop-Methode sollst du überhaupt nicht verwenden. Der Code mit der boolean-Variable ist schon richtig. Wenn du den Thread stoppen willst, setzt du ihn auf false.

Liebe Grüße
Reality
 
Am besten verwendest du isInterrupted:
Code:
public void run()
{
    while (! isInterrrupted())
     {
        System.out.println("running");
     }
}

Thread stoppen:
Code:
myThread.interrupt();
 
Was ist aber, wenn ein Thread nur einen Befehl, zB ein großes Bild laden, durchzuführen hat. Wie kann man denn das sauber abbrechen?
 
hm dann musst du immer wieder wärend dem laden überpfüfen ob interrupted worden ist und wenn ja den thread abbrechen.....

hm naja im oben genannten beispiel kann man nicht mehr abbrechen...

aber mit isInterrupted() wird glaub ich das interruptet flag wieder zurückgesetzt.... also kann man "weitermachen"
 
Hallo und erstmal danke für eure Antworten.

@Reality: Mir ist halt nicht ganz klar wo ich die Variable setzen und wo modifzieren muss, wenn ich den Thread über ein Runnable-Objekt instantiiere. Muss das im Runnable-Objekt selbst geschehen (bspw. in seiner stop()-Methode). Muss ich dann die stop()-Methode des Runnable-Objekts aufrufen statt die des 'eigentlichen' Thread?

@foobar: interrupt() sollte die Aufgabe soweit erfüllen. In meinem Fall ist es nicht notwendig, einen einmal unterbrochenen Thread wieder fortzusetzen, von daher werd ich mich wohl für diese Lösung entscheiden. Wichtig ist mir einfach nur, dass der Thread sauber und ohne die Möglichkeit, inkonsistente Daten zu haben, beendet wird. Wenn interrupt() das macht, ist es genau das Richtige.

Danke nochmal und noch nen schönen Abend,
viele Grüsse JBubble
 
aja zu interrupt sein noch anzumerken das er wenn der thread zb in einem sleep ist, eine interrupted exception geworfen wir....
 
warum soll man eigentlich einen thread net mit stop stoppen?
der befehl hätte ja den richtigen namen dazu 😉
 
weil er ihn abwürgt und das kann zu inkonsistenten Daten führen. bei interrupt bittet man den Thread nur aufzuhüren, also kann er seine aktion zuerst noch beenden...
 
aso, und wenn ich es so mache

Code:
new Thread(new Thread(){
public void run(){
//funktionen
.....
stop(); //hier ist es einfach aus
}}).start();
hier würge ich ihn ja nicht ab, oder brauche ich hier gar kein stop(); ?
 
hbrauchst du kein stop, da sich der thrasd selbst beendet wenn alle funktionen durchlaufen sind. man benötigt es eigentlich nur, wenn der Thread eine while schleife enthält.
 
Eigentlich soll man einen Thread gar nicht "stoppen" bzw. "abwürgen"!

Lass ihn auf eine gemeinsame threadsichere Ressource zugreifen, die ein Flag enthält, das ihm sagt, ob er noch weiterlaufen soll (also im obigen Beispiel etwa "running", nur mit der Möglichkeit, "running" von aussen zu manipulieren)
 
Um das Thema eindeutig zu klären, wäre ein Beispielcode, der
aufzeigt, wie man einen Thread stoppt und selbigen fortsetzt
sehr interessant.
 
für dich mach ich doch alles 😉:

Code:
class ThreadusInterruptus extends Thread {

	public void run() {
		System.out.println("Der Anfang");

		while (true) {
			if(isInterrupted())
				break;

			System.out.println("Hurra");

			try {
				Thread.sleep(500);
			}
			catch (InterruptedException e) {
				interrupt();
			}
		}

		System.out.println("Das Ende");
	}

	public static void main(String args[]) {
		ThreadusInterruptus t = new ThreadusInterruptus();

		t.start();

		try {
			Thread.sleep(2000);
		}
		catch (InterruptedException e) {}

		t.interrupt();
	}
}

kommentar:
"Das Ende" wird ausgegeben, was heisst, dass der Thread nicht abgewürgt wurde, sonder höflich gebittet wurde und seine Angelegenheite benden konnte
 
Jetzt wollte ich gerade ein Beispiel schreiben, dass zeigt, dass Thread#stop schlecht ist, weil noch locks bestehen könnten, merke aber dank dem Beispiel, dass die Methode die locks wieder freigibt 😉
 
Also ich möchte jetzt doch noch mal genauer nachfragen, weil ich entweder total auf dem Schlauch stehe oder einfach zu wenig Erfahrung mit solchen Dingen habe:

Vom Prinzip her ist mir das Beenden vollkommen klar: Eine gemeinsame Ressource (bspw. eine Variable running) wird irgendwann auf false gesetzt, und der Thread beendet sich. Wenn ich eine Klasse hab, die von Thread erbt, ist das auch alles kein Problem, aber wie mache ich das mit einer Klasse, die Runnable implementiert? Ich schreibe hier mal ein konkretes Beispiel auf und würd mich freuen wenn mir jemand den entscheidenden Hinweis gibt:

Das Runnable-Objekt:
Code:
public class MyThread implements Runnable {

  public void run() {
    for(int i=0; i<10; i++) {
      System.out.println(i);
        try {
          Thread.sleep(1000);
        }
        catch(Exception ex) {}
    }
  }
}

Der Code aus dem es aufgerufen wird:
Code:
class IrgendWas {
  Thread t;

  public void startThread() {
    // hier wird der Thread gestartet
    t = new Thread(new MyThread());
    t.start();
  }

  public void stopThread() {
    // und hier soll der Thread gestoppt werden --> nur wie?
  }
}

Ich kann in stopThread() ja nicht t.stop() aufrufen, und eine direkte Referenz auf das Runnable-Objekt hab ich auch nicht. Klar, wär kein Problem das umzuschreiben - müsste ich dann die stop()-Methode des Runnable-Objekts aufrufen und darin die Variable running auf false setzen?

Nochmal herzlichen Dank für eure Hilfe,
viele Grüsse
JBubble
 
Code:
public class MyThread implements Runnable {

  public void run() {
   while (! Thread.currentThread().isInterrupted()) {
    for(int i=0; i<10; i++) {
      System.out.println(i);
        try {
          Thread.sleep(1000);
        }
        catch(Exception ex) {}
    }
  }
  Thread.currentThread().interrupt();
 }
}

this... Würde wohl auch gehen anstatt currentThread


Code:
class IrgendWas {
  Thread t;

  public void startThread() {
    // hier wird der Thread gestartet
    t = new Thread(new MyThread());
    t.start();
  }

  public void stopThread() {
    t.interrupt();
  }
}
 
Tut mir leid, aber der Code funktioniert nicht wie erwartet.

In diesem Fall würde die for-Schleife ja auch zu Ende laufen, wenn der Thread unterbrochen wurde. Ich möchte allerdings, dass die for-Schleife unterbrochen wird.

Auch ein Konstrukt wie

Code:
for(int i=0; i<10; i++) {
  if(Thread.currentThread().isInterrupted()) {
    break;
  }
  // usw.
}

hält den Thread einfach nach einem t.interrupt() nicht an. Oben hat mal einer geschrieben dass eine Exception geworfen wird falls der Thread gerade schläft (was dieser ja fast ausschließlich tut), doch selbst wenn ich einen try-catch-Block um das t.interrupt() baue fange ich keine Exception.
Btw., wenn ich deine Lösung nehme hört der Thread nie mehr auf zu laufen ... irgendwie haut das mit interrupt() nicht hin. Wo könnte der Fehler liegen?
this darf ich statt currentThread() übrigens nicht nehmen, da das Objekt selbst (MyThread) keine isInterrupted()-Methode kennt. Runnable verlangt nur eine run()-Methode.
Achja, falls es was hilft, ich verwende das JDK 1.4.2_04 von Sun.

Viele Grüsse,
JBubble
 
JBubble hat gesagt.:
@Reality: Mir ist halt nicht ganz klar wo ich die Variable setzen und wo modifzieren muss, wenn ich den Thread über ein Runnable-Objekt instantiiere. Muss das im Runnable-Objekt selbst geschehen (bspw. in seiner stop()-Methode). Muss ich dann die stop()-Methode des Runnable-Objekts aufrufen statt die des 'eigentlichen' Thread?
Die boolean-Variable ist global, sonst kannst du ja von außen nicht zugreifen und die Variable auf false setzen, damit die Schleife aufhört.
Und die stop-Methode wird NICHT benutzt, sondern NUR die boolean-Variable auf false gesetzt und schon hört die Schleife in dem Thread auf. Wenn du den Thread fortführen willst, setzt du sie wieder auf true.

Liebe Grüße
Reality
 
Danke Reality, so scheint das erstmal zu laufen 🙂.

Würde mich trotzdem mal interessieren warum das mit interrupt() nicht funktioniert hat.

Wünsch euch noch nen schönen Abend,
viele Grüsse
JBubble
 
Code:
public class myThread
extends AnyClass      //kann natürlich auch "Thread" sein. Allerdings braucht man dann 
implements Runnable   //Runnable nicht mehr!
{
    private boolean stopped = false; //aus Synchronisationsgründen "private"
    private boolean paused = false;  //aus Synchronisationsgründen "private"
    private Thread t;                //aus Sicherheitsgründen "private"

    public void run()
    {
        while (!stopped) {
            //Running Code...
            //stopped und paused können immer wieder abgefragt werden
            while (!paused) {
                //Noch mehr Running Code...
                //stopped und paused können selbstverständlich auch hier abgefragt werden
            }
        }
        t.interrupt();
        t = null; //forcing Thread to be KILLED! Nicht wirklich wichtig;
    }

    public synchronized boolean isStopped()
    {
        return stopped; //Durch diese Methode lässt sich von paused von Aussen
                        //abfragen. Durch synchronized wird das 'ne ganz
                        //saubere Sache.
    }

    public synchronized boolean isPaused()
    {
        return paused; //Siehe oben
    }

    public synchronized void Stop() // Beachten Sie!!! die Schreibweise von "Stop"!!!
    {
        stopped = false;
        paused = true; //Sonst bleibt der Thread möglicherweise in einer durch paused
                       //angehaltenen Schleife stehen.
    }

    public synchronized void Start()
    {
        if (stopped && t.isInterrupted()) { //Wenn das immer false ergibt,
                                            //"t.isInterrupted()" durch "t == null"
                                            //ersetzen. Nun ist der Thread-Killer
                                            //in run() NOTWENDIG! (Doch wirklich wichtig)
            t = new Thread(this);
            t.start();
            stopped = false; //mit "stopped = paused = false;" würden beide Variablen
                             //auf ein Object instanziert. Die Änderung eines Wertes
            paused = false;  //wirkt sich dann auch auf den anderen aus.
        }
    }

    public synchronized void Pause()
    {
        paused != paused; // oder paused = !paused;
    }
}
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben