Wie hier gesehen werden kann, gibt es nur einen geraden Asuführungsfluß. Oft
wäre es allerdings sinnvoll, mehrere solcher Flüsse zu haben. Beispielsweise
das Einladen einer Datei, kann beträchtliche Zeit rauben, genauso wie das
abholen von Ressourcen aus dem Netz. Ein weiteres Beispiel sind Kommandozeilen,
bei weöchen es für den Benutzer sehr irritierend ist, wenn diese nur langsam
reagiert.
Je nach Thread-Modell des Betriebssystems werden nun die Prozesse idealerweise
nebeneinander ausgeführt. Wodurch z.B. der langsame Prozeß nicht mehr z.B. die
Benutzereingabe verlangsamt.
In den meisten Fällen wird auf einem mono-Prozessorsystem gearbeitet, selbst wenn es sich um ein mehr-Prozessorsystem handelt, können die Anzahl verlangter Threads die Anzahl installierter Prozessoren übersteigen. In diesem Fall wird das parallele Verarbeiten nur simuliert.
D.h. ein Thread läuft nur dann wenn gerade die Kapazität dazu frei ist, d.h. ein anderer Thread gerade Zyklen-freigibt (mit yield();), anhält oder sich auflöst; auf Betriebsysteme die nach dem sogenannten Time-slicing Verfahren arbeiten, sit eine weitere Möglichkeit, daß ein Thread seine maximale Anzahl Zyklen aufgebraucht hat. Stehen mehrere threads zur bearbeitung aus wird der mit der höchsten Priorität ausgewählt. Muß zwischen gleich-prioritären Threads gewählt werden, werden sie zyklisch ausgewählt.
Es ist möglich (mit setPriority) die Priorität eines Threads zu verändern, sonst behält dieser die die er von seinem Elter bekommen hat.
public class SimpleThread extends Thread
{
    public SimpleThread(String str)
    {
      super(str);
    }
    public void run()
    {
       for (int i = 0; i < 10; i++)
       {
          System.out.println(i + " " + getName());
          try { sleep((long)(Math.random() * 1000)); }
          catch (InterruptedException e) {}
       }// for (int i = 0; i < 10; i++)
       System.out.println("DONE! " + getName());
    }// public void run()
}// public class SimpleThread extends Thread
Diese Klasse erbt von Thread, das auffälligste ist, daß die Methode run entsprechend ausgebaut werden muß, dies ist die Methode, welche aufgerufen wird wenn der Thread gestartet wird. Ist die Ausführung in run() zuende, stirbt auch der Thread. In diesem Fall wird der Thread 10 mal aufweckbar sein, danach wird er zu existieren aufgehört haben.
Der Inhalt der run-Methode ist entsprechend: eine Schleife mit 10 Durchläufen, eine Ausgabe, x mal 1s warten und weiterschleifen.
Um diese Klasse zu testen, kann folgendes Programm benutzt werden:
public class TwoThreadsTest
{
    public static void main (String[] args)
    {
        new SimpleThread("Jamaica").start();
        new SimpleThread("Fiji").start();
    }// public static void main (String[] args)
}// public class TwoThreadsTest
Damit bekäme man beispielsweise folgende Ausgabe:
0 Jamaica 0 Fiji 1 Fiji 1 Jamaica 2 Fiji 2 Jamaica 3 Fiji 3 Jamaica 4 Jamaica 4 Fiji 5 Jamaica 5 Fiji 6 Jamaica 6 Fiji 7 Fiji 8 Fiji 9 Fiji 7 Jamaica 8 Jamaica 9 Jamaica DONE! Fiji DONE! Jamaica
import java.awt.Graphics;
import java.util.*;
import java.text.DateFormat;
import java.applet.Applet;
public class Clock extends Applet implements Runnable {
    private Thread clockThread = null;
    public void start() {
        if (clockThread == null) {
            clockThread = new Thread(this, "Clock");
            clockThread.start();
        }
    }
    public void run() {
        Thread myThread = Thread.currentThread();
        while (clockThread == myThread) {
            repaint();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e){
            // the VM doesn't want us to sleep anymore,
            // so get back to work
            }
        }
    }
    public void paint(Graphics g) {
        // get the time and convert it to a date
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();
        // format it and display it
        DateFormat dateFormatter = DateFormat.getTimeInstance();
        g.drawString(dateFormatter.format(date), 5, 10);
    }
    // overrides Applet's stop method, not Thread's
    public void stop() {
        clockThread = null;
    }
}
Hier wird die Methode run implementiert, und die Konformität dieser Klasse zum
Typ Runnable erzwungen indem das Interface Runnable implementiert wurde.
Damit ist es möglich dieses Objekt einem Thread zu übergeben, dessen einzige Aktivität das Ausführen der Run-Methode unseres Objektes ist.
isAlive()-Methode abzufragen, kommt false
zurück ist der Thread entweder ein neuer Thread oder schon tot.
Folgendes Bild illustriert diesen Zyklus:
IllegalThreadStateException-Fehler.
start() gestartet, diese ruft die Methode
run() des Threads auf. Jetzt erst werden die Systemressourcen
angelegt und die Ausführung beginnt.
Entsprechend kann ein Thread nur dann in den laufenden Zustand gebracht werden, wenn der inverse Weg beschritten wird. D.h.
Nun ist es aber in der Regel der Fall, daß ein Thread von den Daten, die ein anderer produzieren kann abhängig. D.h. die Threads müssen sich untereinander "absprechen" um keine Miß-lesungen zu machen.
Dies ist ein komplexes Thema, welches außer Software-Mechanismen wie
Object-locking (dank des synchronized Modificators) oder Semaphoren (Jeder
Thread ist sein eignener Semaphor, das Auslösen erfolgt durch die
wait-Methode auch viel Designphilosophie einschließt um Probleme
wie Dead-Locks (alle Threads manövrieren sich in einen Zustand, bei dem alle
auf alle warten und nichts mehr passiert)
Der Timer wird mit start() gestartet, und mit
stop() gestoppt.
Document mit wml erzeugt von Bruno Böttcher unter Benutzung von öffentlichen Dokumenten.