24.8
Beenden von Threads |
|
Um einen
Thread zu beenden, liegt es nahe, die
stop()-Methode
der Klasse Thread
zu benutzen. Tatsächlich führt ihr Aufruf zu einem sofortigen Abbruch des
Threads, wobei alle Sperren aufgehoben werden. Nun ist die
stop()-Methode
deprecated (missbilligt). Die Fa. SunTM rät also dazu, diese
Methode nicht mehr zu benutzen. Was ist der Grund dafür? Nun, wenn ein
Thread, der gerade eine Sperre auf ein Objekt hält, komplexere und u. U.
langwierige Operationen ausführen. Wird dieser Thread unvermittelt
gestoppt, so lässt er das Objekt, auf das er eine Sperre hatte, unter
Umständen in einem nicht definierten Zustand. Das ist so, als wollten wir
ein Auto, das sich mitten in der Fahrt befindet, ohne gezieltes Anhalten,
einfach ausschalten. Wir zeigen dies an einem Beispiel. |
|
Download: TestThread1. java |
|
Bemerkungen | Die
Klasse TestThread ist der Klasse Thread nachempfunden: sie emplentiert
Runnable, besitzt den nicht extra implementierten Standardkonstruktor und
die Methoden start(),
stop()
und run().
|
start() | Was
passiert noch? Unsere Klasse aggregiert ein
Thread-Objekt.
Warum tun wir das? Die in unserer Klasse implementierte Methode
start()soll
die Methode start()
der Klasse Thread
aufrufen. Das geht aber nur dann, wenn das Objekt der Klasse
TestThread1
von einem Thread-Objekt kontrolliert wird. Deshalb wird in unserer Klasse
ein Objekt thread
der Klasse Thread
deklariert und zunächst auf null
gesetzt. Es existiert also noch keine Referenz auf dieses Objekt. Mit
thread = new Thread(this);
in unserer Methode start()
erfolgt dann die Instanziierung und die Übergabe der Instanz unserer
Klasse TestThread
(deshalb
this)
an thread.
Dann können wir den Thread mit der Thread-Methode
start()
starten. |
stop() | Diese Methode ist sehr einfach, sie startet lediglich die Thread-Methode stop(), tut also nichts anderes als die deprecated-Methode. |
run() | Solange
der Thread unser Objekt kontrolliert, wird in der
run()-Methode
eine Schleife ausgeführt: Ausgehend von der 1 wird also hoch gezählt und
die Werte ausgegeben. Damit der Vorgang lange genug geht, wir simulieren
einen langwierige Berechnung, lassen wir den Thread nach jeder
Inkrementierung eine Sekunde 'schlafen'. Das Inkrementieren kann also nur
beendet werden, wenn man den Thread beendet. |
TestKlasse
Download: |
|
Bemerkungen | Unsere
Testklasse erzeugt eine Instanz unseres
TestThreads,
startet diese, wartet 5 Sekunden und stoppt ihn. |
Ausgabe | Thread
gestartet 1 2 3 4 C:\Java Drücken Sie eine beliebige Taste . . . |
Im ersten
Moment wundert, dass nur bis 4 hoch gezählt wurde. Tatsächlich war die
Schleife
gerade dabei, weiter hoch zuzählen,
also sie 'gewaltsam' daran gehindert wurde. Es wurde also nicht die
Schleife beendet sondern die ganze
run()-Methode
abgebrochen. Deshalb fehlt auch die Endausgabe: Thread gestoppt, Lebensdauer: .... |
|
Wir
wollen nun zeigen, wie ein kontrollierter Abbruch eines Threads
implementiert werden kann. |
|
Download: TestThread2.java |
Gegen
über der Klasse TestThread1 verändern wir lediglich die stop()-Methode:
Die Veränderung im Quelltext scheint minimal, inhaltlich passiert aber sehr viel. Satt die deprecated-Methode stop() aus der Klasse Thread zu benutzen, programmieren wir unsere stop() vollkommen neu. Wir halten den Thread dadurch an, dass wir ihm die Referenz entziehen und auf null setzen. Dies geschieht allerdings erst nach der Abfrage thread != null, die erst nach dem Abarbeiten der Thread.sleep(1000) erfolgt.
|
Download: BeendenThread2. java |
|
Hier
haben wir außer den Namen nichts verändert. |
|
Ausgabe | Thread
gestartet 1 2 3 4 5 Thread gestoppt, Lebensdauer: 5017 C:\Java Drücken Sie eine beliebige Taste . . . |
interrupt() | Wir
ergänzen unsere Klasse TestThread um eine Methode
interrupt(),
die ihrerseits interrupt()
der Klasse Thread aufruft. |
Download: TestThread3. java |
|
Bemerkungen | Die
Veränderungen gegenüber
TestThread2 sind gelb markiert.
|
Download: BeendenThread3. java |
|
Ausgabe | Thread
gestartet 1 2 3 4 5 Thread gestoppt, Lebensdauer: 5007 C:\java Drücken Sie eine beliebige Taste . . . |
Diese
Ausgabe können wir erst in ihrer Tragweite erfassen, wenn wir die Zeile
Thread.sleep(5000);
durch Thread.sleep(5500);
ersetzen. |
|
Ausgabe | Thread
gestartet 1 2 3 4 5 Thread interrupted! Thread gestoppt, Lebensdauer: 5508 C:\Java Drücken Sie eine beliebige Taste . . . |
Bemerkungen | Im
zweiten Fall (Thread.sleep(5500))
unterbrach testThread.interrupt()das
Objekt testThread
als seine run()-Methode,
gearde den Aufruf
Thread.sleep(1000) ausführte,
was zu einer InterrptedException führte, die im
catch-Konstrukt
bearbeitet wurde. Im ersten Fall (Thread.sleep(5000))
unterbrach testThread.interrupt()
das Objekt testThread
als seine run()-Methode
gerade nicht den Aufruf
Thread.sleep(1000); ausführte. |
Noch eine Veränderung
Downoad: |
|
Bemerkungen | Gegenüber
BeendenThread3 haben wir testThread.stop(); weggelassen. ThestThread3
wurde unverändert gelassen. |
Thread
gestartet 1 2 3 4 5 Thread interrupted! Thread gestoppt, Lebensdauer: 5007 C:\Java Drücken Sie eine beliebige Taste . . . |
|
Jetzt kommt auch bei Thread.sleep(5000); die Ausgabe Thread interrupted! Das verwundert aber nicht. Der Thread lebt noch, er war nur unterbrochen und deshalb wirft sleep() eine InterruptedException. Die run()-Methode beendet den Thread dann auch, was man an der Ausgabe Thread gestoppt, Lebensdauer: 5007 erkennt. Denn zu dieser Ausgabe gelangt die run()-Methode erst, wenn die while-Schleife beendet ist, und das wiederum ist erst der Fall wenn thread != null falsch und damit thread == null wahr ist. | |
zur Startseite | www.pohlig.de (C) MPohlig 2003 |