Guido Krüger - JAVA 1.1 lernen - Kapitel 10

Previous Page Previous Page TOC TOC Index Next Page Previous Page



Die Klasse Thread

Erzeugen eines neuen Threads

Die Klasse Thread ist Bestandteil des Pakets java.lang und steht damit allen Anwendungen standardmäßig zur Verfügung. Thread stellt die Basismethoden zur Erzeugung, Kontrolle und zum Beenden von Threads zur Verfügung. Um einen konkreten Thread zu erzeugen, muß eine eigene Klasse aus Thread abgeleitet und die Methode run überlagert werden.

Mit Hilfe eines Aufrufs der Methode start wird der Thread gestartet und die weitere Ausführung an die Methode run übertragen. start wird nach dem Starten des Threads beendet, und der Aufrufer kann parallel zum neu erzeugten Thread fortfahren.

Beispiel

Das folgende Beispiel zeigt einen einfachen Thread, der in einer Endlosschleife einen Zahlenwert hochzählt:

class MyThread
extends Thread
{
   public void run()
   {
      int i = 0;
      while (true) {
         System.out.println(i++);
      }
   }
}

public class Example1001
{
   public static void main(String[] args)
   {
      MyThread t = new MyThread();
      t.start();
   }
}

Zunächst wird hier ein neues Objekt vom Typ MyThread instanziert. Die Ausführung eines Threads ist damit vorbereitet, aber noch nicht tatsächlich erfolgt. Erst durch den Aufruf von start wird ein neuer Thread erzeugt und durch einen impliziten Aufruf von run der Thread-Body gestartet. Da das Programm in einer Endlosschleife läuft, läßt es sich nur gewaltsam abbrechen (beispielsweise durch Drücken von STRG+C).

Hinweis

Im Gegensatz zu unseren bisherigen Beispielen wird dieses Programm nicht automatisch beendet, nachdem main beendet wurde. Es gibt eine einfache Regel, die besagt, daß eine Java-Applikation immer dann beendet wird, wenn der letzte Thread beendet wurde, der kein Hintergrund-Thread (Dämon) ist. Da ein einfaches Programm nur einen einzigen Vordergrund-Thread besitzt (nämlich den, in dem main läuft), wird es demnach beendet, wenn main beendet wird. Das Beispielprogramm erzeugt dagegen einen zusätzlichen Vordergrund-Thread und kann damit vom Interpreter erst dann beendet werden, wenn dieser Thread beendet wurde.

Beenden eines Threads

Die übliche Vorgehensweise, einen Thread zu beenden, besteht darin, die Methode stop der Klasse Thread aufzurufen. In diesem Fall wird der Thread angehalten und aus der Liste der aktiven Threads entfernt.

Beispiel

Wir wollen das vorige Beispiel erweitern und den Thread nach zwei Sekunden durch Aufruf von stop beenden:

class MyThread
extends Thread
{
   public void run()
   {
      int i = 0;
      while (true) {
         System.out.println(i++);
      }
   }
}

public class Example1002
{
   public static void main(String[] args)
   {
      MyThread t = new MyThread();
      t.start();
      try {
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        //nichts
      }
      t.stop();
   }
}

In diesem Beispiel kann man gut erkennen, daß der Thread tatsächlich parallel ausgeführt wird. Nach dem Aufruf von start beginnt einerseits die Zählschleife, andererseits fährt das Hauptprogramm mit dem Aufruf der sleep-Methode fort. Beide Programmteile laufen also parallel ab.

Unterbrechen eines Threads

Mit Hilfe der Methoden suspend und resume ist es möglich, einen Thread vorübergehend zu unterbrechen und fortzusetzen. Durch suspend wird die Ausführung unterbrochen, und durch resume wird der Thread (genauer gesagt: die Methode run) an der Stelle fortgesetzt, an der die Unterbrechung erfolgte.

Beispiel

Das folgende Programm realisiert zwei Threads, die parallel Bildschirmausgaben erzeugen. Jeder der beiden Threads wird dabei in regelmäßigen Abständen unterbrochen und nach einer kurzen Pause fortgesetzt:

class MyThread1003
extends Thread
{
   String spaces;

   public MyThread1003(String spaces)
   {
      super();
      this.spaces = spaces;
   }

   public void run()
   {
      int i = 0;

      while (true) {
         System.out.println(spaces+getName()+": "+i++);
         try {
            Thread.sleep(100);
         } catch (InterruptedException e) {
            //nichts
         }
      }
   }
}

public class Example1003
{
   public static void main(String[] args)
   {
      MyThread1003 t1 = new MyThread1003("");
      MyThread1003 t2 = new MyThread1003("                    ");
      t1.start();
      t2.start();
      for (int i=0; i<10; ++i) {
         try {
            Thread.sleep(550);
         } catch (InterruptedException e) {
            //nichts
         }
         t1.suspend();
         try {
            Thread.sleep(550);
         } catch (InterruptedException e) {
            //nichts
         }
         t1.resume();
      }
      t1.stop();
      t2.stop();
   }
}

Die eigentliche Ablauflogik des Programms befindet sich in der Klasse MyThread1003. Hier werden in einer Endlosschleife der Name des Threads und ein fortlaufender Zähler ausgegeben. Um die Ausgabe beider Threads zu unterscheiden, kann an den Konstruktor ein Leerstring übergeben werden, der zur Einrückung der Ausgabe dient. Das Hauptprogramm startet beide Threads und unterbricht den ersten dann periodisch im Abstand von 550 ms.

Die Ausgabe des Programms lautet:

Thread-1: 0
                    Thread-2: 0
Thread-1: 1
                    Thread-2: 1
Thread-1: 2
                    Thread-2: 2
Thread-1: 3
                    Thread-2: 3
Thread-1: 4
                    Thread-2: 4
Thread-1: 5
                    Thread-2: 5
                    Thread-2: 6
                    Thread-2: 7
                    Thread-2: 8
                    Thread-2: 9
                    Thread-2: 10
Thread-1: 6
                    Thread-2: 11
Thread-1: 7
                    Thread-2: 12
Thread-1: 8
                    Thread-2: 13
Thread-1: 9
                    Thread-2: 14
Thread-1: 10
                    Thread-2: 15
Thread-1: 11
                    Thread-2: 16
                    Thread-2: 17
                    Thread-2: 18
                    Thread-2: 19
                    Thread-2: 20
Thread-1: 12
                    Thread-2: 21
Thread-1: 13
                    Thread-2: 22
...

Hinweis

Man kann hier sehr gut erkennen, daß der erste Thread nach jedem fünften bis sechsten Durchlauf unterbrochen wird, der zweite Thread jedoch ohne Pause fortfährt. Zu beachten ist, daß das exakte Verhalten dieses Programms nicht mehr allein auf der Basis des zugrundeliegenden Java-Codes bestimmt werden kann. Statt dessen spielen weitere Einflußfaktoren, wie beispielsweise die Auflösung des System-Timers, die Auslastung des Rechners und die Implementierung des Schedulers, eine Rolle.

Weitere Methoden

sleep

Sowohl innerhalb der Threads als auch innerhalb der Methode main wird ein Aufruf von Thread.sleep verwendet, um das Programm pausieren zu lassen. sleep ist eine statische Methode der Klasse Thread, die mit einem oder zwei Parametern aufgerufen werden kann:

public static void sleep(long millis);
public static void sleep(long millis, int nanos);

Die erste Version sorgt dafür, daß der aktuelle Prozeß für die (in Millisekunden angegebene) Zeit unterbrochen wird. Die zweite erlaubt eine noch genauere Eingabe der Wartezeit, indem auch Bruchteile im Nanosekundenbereich angegeben werden können. In beiden Fällen wird die tatsächlich erzielbare Genauigkeit allerdings durch Hardwarerestriktionen der Zielmaschine begrenzt. Im Fall von MS-DOS/Windows entspricht sie in der Regel der Genauigkeit des System-Tickers, liegt also bei etwa 55 ms.

Hinweis

Die Kapselung des Aufrufs von Thread.sleep innerhalb eines try-catch-Blocks ist erforderlich, weil sleep nach Ablauf der Zeit eine Ausnahme vom Typ InterruptedException erzeugt. Ohne den try-catch-Block würde diese an den Aufrufer weitergegeben werden. Als Klassenmethode kann sleep aufgerufen werden, ohne daß eine Instanz der Klasse Thread verfügbar ist. Insbesondere kann die Methode auch dazu verwendet werden, das Hauptprogramm pausieren zu lassen, das ja nicht explizit als Thread erzeugt wurde. Dies funktioniert deshalb, weil beim Starten eines Java-Programms automatisch ein Thread für die Ausführung des Hauptprogramms angelegt wurde.

isAlive

Mit dieser Methode kann festgestellt werden, ob der aktuelle Thread noch läuft.

public final boolean isAlive();

isAlive gibt immer dann true zurück, wenn der aktuelle Thread gestartet, aber noch nicht wieder beendet wurde. Beendet wird ein Thread, wenn das Ende der run-Methode erreicht ist oder wenn die Methode stop aufgerufen wurde.

join

public final void join()
throws InterruptedException;

Die Methode join wartet auf das Ende des Threads, für den sie aufgerufen wurde. Sie ermöglicht es damit, einen Prozeß zu starten und (ähnlich einem Funktionsaufruf) mit der weiteren Ausführung so lange zu warten, bis der Prozeß beendet ist. join gibt es auch mit einem long als Parameter. In diesem Fall wartet die Methode maximal die angegebene Zeit in Millisekunden und fährt nach Ablauf der Zeit auch dann fort, wenn der Prozeß noch nicht beendet ist.


Previous Page Previous Page Page Top TOC Index Next Page Previous Page

(C) 1997 Guido Krueger, "Java 1.1 lernen", Addison-Wesley, Bonn, 1997