10.02 Einen Thread starten

Ein Thread ist prinzipiell eine ganz gewöhnliche Klasse, die sich im Package java.lang befindet. Bei der Initialisierung wird ihr ein Objekt übergeben, dessen Klasse das Interface java.lang.Runnable implementieren muss. Dieses Runnable-Objekt enthält den eigentlich auszuführenden Code. Über den Aufruf der start-Methode des Thread-Objekts wird der Thread letztendlich gestartet.

Die Runnable-Schnittstelle

Eine Klasse, die das Interface Runnable implementiert, muss lediglich eine einzige Methode beinhalten – die run-Methode. Diese Methode wird beim Starten eines neuen Threads aufgerufen. Als Beispiel dienen zwei einfache Runnable-Klassen. Die Erste (RandomRunnable) gibt zehn Zufallszahlen aus, die von Math.random() generiert werden:

package de.jbb.threads;

public class RandomRunnable implements Runnable {

  public void run() {
    for (int i = 0; i < 10; i++) {
      System.out.println("RandomRunnable: " + Math.random());
    }
  }
}

Die Zweite (CounterRunnable) gibt die Zahlen 1-20 in einer Schleife aus:

package de.jbb.threads;

public class CounterRunnable implements Runnable {

  public void run() {
    for (int i = 1; i <= 20; i++) {
      System.out.println("CounterRunnable: " + i);
    }
  }
}

Threads laufen lassen

Um einen Thread parallel zum eigentlichen Programmverlauf (der selbstverständlich auch in einem Thread läuft) auszuführen, muss ein Runnable-Objekt in einen Thread verpackt werden. Das Thread-Objekt wird dann via start() ausgeführt. Erzeugt man von den beiden Runnable-Klassen neue Objekte, lässt diese in jeweils einem separatem Thread laufen, und zählt gleichzeitig noch in einer Schleife ohne extra Thread,

package de.jbb.threads;

public class ThreadTest {

  public static void main(String[] args) {

    Thread counter = new Thread(new CounterRunnable());
    Thread random = new Thread(new RandomRunnable());

    random.start();
    counter.start();
    for (int i = 20; i > 0; i--) {
      System.out.println("ThreadTest: " + i);
    }
  }
}

könnte bspw. eine solche Ausgabe entstehen (gekürzt):

ThreadTest: 20
ThreadTest: 19
ThreadTest: ...
ThreadTest: 11
ThreadTest: 10
RandomRunnable: 0.7880051119138216
RandomRunnable: ...
RandomRunnable: 0.9195788240199284
CounterRunnable: 1
CounterRunnable: 2
CounterRunnable: ...
CounterRunnable: 19
CounterRunnable: 20
ThreadTest: 9
ThreadTest: 8
RandomRunnable: 0.6763623130152083
ThreadTest: 7
ThreadTest: ...
ThreadTest: 1

Beim nächsten Durchlauf der Main-Methode von ThreadTest, wird das Ergebnis vermutlich wieder komplett anders aussehen, da Threads eben parallel verlaufen und ihre Laufzeit somit nur schlecht berechenbar ist. Auch benötigt ein Thread eine gewisse Startzeit, bevor es losgehen kann.

Ein Thread „ohne“ Runnable

Auch wenn es meistens als guter Stil angesehen wird, eine eigene Runnable-Klasse zu verwenden, können Sie einen Thread direkt überschreiben und nebenläufig Ausführen. Dies ist möglich, weil Thread selbst Runnable implementiert. In diesem Fall müssen Sie in Ihrer Klasse natürlich auch die run-Methode überschreiben:

package de.jbb.threads;

public class MyThread extends Thread {

  @Override
  public void run() {
    for (int i = 1; i <= 20; i++) {
      System.out.println("MyThread: " + i);
    }
  }
}

Zum Testen:

package de.jbb.threads;

public class ThreadTest {

  public static void main(String[] args) {

    Thread mythread = new MyThread();
    mythread.start();

    for (int i = 20; i > 0; i--) {
      System.out.println("ThreadTest: " + i);
    }
  }
}

Ausgabe (so oder so ähnlich, gekürzt):

ThreadTest: 20
ThreadTest: 19
ThreadTest: 18
MyThread: 1
MyThread: 2
MyThread: ...
MyThread: 17
MyThread: 18
ThreadTest: 17
ThreadTest: 16
ThreadTest: ...
ThreadTest: 2
ThreadTest: 1
MyThread: 19
MyThread: 20

run() anstelle von start()

Mit start starten Sie einen Thread, in der run-Methode befindet sich Ihr Code. Soweit so klar. Folglich muss die start-Methode auch irgendwann die run-Methode aufrufen. Aber was passiert, wenn Sie versehentlich run anstelle von start aufrufen? Probieren Sie es aus:

package de.jbb.threads;

public class ThreadTest {

  public static void main(String[] args) {

    Thread counter = new Thread(new CounterRunnable());
    Thread random = new Thread(new RandomRunnable());

    random.run();
    counter.run();
    for (int i = 20; i > 0; i--) {
      System.out.println("ThreadTest: " + i);
    }
  }
}

Ausgabe (gekürzt):

RandomRunnable: 0.3831618083925371
RandomRunnable: 0.8759089956232685
RandomRunnable: ...
RandomRunnable: 0.06849475366383484
RandomRunnable: 0.6868276713554855
CounterRunnable: 1
CounterRunnable: 2
CounterRunnable: ...
CounterRunnable: 19
CounterRunnable: 20
ThreadTest: 20
ThreadTest: 19
ThreadTest: ...
ThreadTest: 2
ThreadTest: 1

Ihr Code wird trotzdem ausgeführt. Allerdings sequentiell nacheinander und nicht parallel wie man es von einem Thread erwartet. Dadurch, dass Ihr Code trotzdem funktioniert, ist dies vor allem am Anfang eine Fehlerquelle, die Sie nicht aus den Augen verlieren sollten.

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.