MyThread extends Thread – oder implements Runnable?

© ArturVerkhovetskiy – Shotshop.com

In der vorigen Diskussion haben wir gesehen, wie man Threads in Java durch die Vererbung von der Thread-Klasse und durch die Implementierung des Runnable-Interfaces erstellen kann. In diesem Beitrag vertiefen wir unser Verständnis dieser beiden Ansätze und sehen uns die Unterschiede zwischen ihnen an.

MyThread extends Thread

Wenn Sie ein neues Thread durch die Vererbung von der Thread-Klasse erstellen, erstellen Sie tatsächlich ein neues Objekt, das als Thread fungiert.

class MyThread extends Thread {
  public void run() {
    for (int i = 0; i < 10; i++) {
      System.out.println(Thread.currentThread().getId() + " Value " + i);
    }
  }
}

public class Main {
  public static void main(String[] args) {
    MyThread t1 = new MyThread();
    t1.start();
    MyThread t2 = new MyThread();
    t2.start();
  }
}

MyThread implements Runnable

Im Gegensatz dazu erstellt die Implementierung des Runnable-Interfaces keinen neuen Thread. Stattdessen definiert es eine Aufgabe, die von einem Thread ausgeführt werden kann. Hier ist ein entsprechendes Beispiel:

class MyRunnable implements Runnable {
  public void run() {
    for (int i = 0; i < 10; i++) {
      System.out.println(Thread.currentThread().getId() + " Value " + i);
    }
  }
}

public class Main {
  public static void main(String[] args) {
    Thread t1 = new Thread(new MyRunnable());
    t1.start();
    Thread t2 = new Thread(new MyRunnable());
    t2.start();
  }
}

In diesem Code definieren wir eine Klasse MyRunnable, die das Runnable-Interface implementiert. Wir überschreiben die run-Methode genauso wie zuvor. Um die Aufgabe auszuführen, erstellen wir eine neue Instanz von Thread und übergeben eine Instanz von MyRunnable an den Konstruktor.

Unterschiede zwischen den beiden Ansätzen

In der Praxis wird oft empfohlen, Runnable zu verwenden, da es flexibler und kompatibler mit dem Thread-Pooling und anderen fortschrittlichen Techniken ist. Aber es gibt auch Situationen, in denen die Verwendung von Thread sinnvoll sein kann. Es hängt von den spezifischen Anforderungen Ihres Programms ab.

Die Nutzung der Klasse Thread anstelle des Runnable-Interfaces kann in bestimmten Fällen sinnvoll sein, insbesondere wenn man die erweiterte Funktionalität der Thread-Klasse nutzen möchte.

Methoden der Thread-Klasse, die nicht im Runnable-Interface zur Verfügung stehen

Eine Situation, in der die Verwendung von Thread vorteilhaft sein kann, ist, wenn man bestimmte Thread-spezifische Methoden verwenden muss, wie zum Beispiel setPriority(), getPriority(), setName(), getName(), setDaemon(), isDaemon(), die direkt in der Thread-Klasse definiert sind. Diese Methoden sind nicht in der Runnable-Schnittstelle verfügbar, da sie speziell auf die Verwaltung von Threads abzielen:

class MyThread extends Thread {
  public MyThread(String name) {
    setName(name); // Setzen des Thread-Namens
  }
  
  public void run() {
    System.out.println("Thread Name: " + getName());
  }
}

public class Main {
  public static void main(String[] args) {
    MyThread t1 = new MyThread("MyThread 1");
    t1.start();
  }
}

In diesem Code definieren wir eine Klasse MyThread, die von Thread erbt und den Thread-Namen setzt, wenn sie instanziiert wird. Dies wäre nicht möglich, wenn wir Runnable implementieren würden, da das Setzen des Thread-Namens eine spezifische Methode der Thread-Klasse ist.

Es ist jedoch zu beachten, dass obwohl die Thread-Klasse zusätzliche Methoden bereitstellt, die Runnable-Schnittstelle in der Regel die bevorzugte Wahl für die Erstellung von Threads ist, insbesondere in Anwendungen, die eine hohe Grad an Concurrency benötigen. Dies liegt daran, dass die Implementierung des Runnable-Interfaces es ermöglicht, die Klasse mit anderen Interfaces zu kombinieren und die Einschränkung der Einzelvererbung in Java zu umgehen. Darüber hinaus ermöglicht die Verwendung von Runnable die bessere Zusammenarbeit mit Thread-Pools und parallelen Frameworks wie dem Executor Framework in Java.

Zusammenfassung

Die Wahl zwischen der Vererbung von Thread und der Implementierung von Runnable hängt von den spezifischen Anforderungen Ihres Programms ab. Durch ein tieferes Verständnis der Unterschiede und Anwendungsfälle dieser beiden Ansätze können Sie effizientere und ansprechendere Multithread-Anwendungen in Java erstellen.