Frage "Implementiert Runnable" vs. "erweitert Thread"


Von der Zeit, die ich mit Threads in Java verbracht habe, habe ich diese zwei Möglichkeiten gefunden, Threads zu schreiben:

Mit implements Runnable:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

Oder mit extends Thread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

Gibt es einen signifikanten Unterschied in diesen beiden Code-Blöcken?


1794
2018-02-12 14:28


Ursprung


Antworten:


Ja: Geräte Runnable ist der bevorzugte Weg, es zu tun, IMO. Du spezialisierst nicht wirklich das Verhalten des Threads. Du gibst ihm nur etwas zum Laufen. Das bedeutet Zusammensetzung ist der philosophisch "reiner" Weg zu gehen.

Im praktisch Begriffe bedeutet, dass Sie implementieren können Runnable und erstrecken sich auch von einer anderen Klasse.


1446
2018-02-12 14:32



tl; dr: implementiert Runnable ist besser. Der Vorbehalt ist jedoch wichtig

Im Allgemeinen würde ich empfehlen, etwas wie Runnable eher, als Thread weil es Ihnen erlaubt, Ihre Arbeit nur lose mit Ihrer Wahl der Nebenläufigkeit verbunden zu halten. Zum Beispiel, wenn Sie eine verwenden Runnable und entscheide später, dass dies in der Tat nicht seine eigene erfordert Thread, können Sie einfach threadA.run () aufrufen.

Vorbehalt: Hier rate ich dringend davon ab, rohe Threads zu verwenden. Ich bevorzuge den Gebrauch von Anrufer und Zukunftsaufgaben (Aus dem Javadoc: "Eine auflösbare asynchrone Berechnung"). Die Integration von Timeouts, korrektem Cancelling und dem Thread-Pooling der modernen Concurrency-Unterstützung sind für mich viel nützlicher als Stapel von rohen Threads.

Nachverfolgen: da ist ein FutureTask Konstrukteur Damit können Sie Runnables verwenden (wenn Sie das am besten wissen) und dennoch die Vorteile der modernen Tools für den gemeinsamen Zugriff nutzen. Um das Javadoc zu zitieren:

Wenn Sie kein bestimmtes Ergebnis benötigen, sollten Sie Konstruktionen des Formats verwenden:

Future<?> f = new FutureTask<Object>(runnable, null)

Also, wenn wir ihre ersetzen runnable mit Ihrem threadA, wir bekommen folgendes:

new FutureTask<Object>(threadA, null)

Eine weitere Option, mit der Sie näher an Runnables bleiben können, ist a ThreadPoolExecutor. Du kannst den ... benutzen ausführen Methode, um eine Runnable zu übergeben, um "die gegebene Aufgabe irgendwann in der Zukunft" auszuführen.

Wenn Sie versuchen möchten, einen Threadpool zu verwenden, wird das obige Codefragment ungefähr wie folgt aussehen (mithilfe des Executors.newCachedThreadPool () Fabrikmethode):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

494
2018-02-12 14:37



Moral der Geschichte:

Übernehmen nur, wenn Sie ein bestimmtes Verhalten überschreiben möchten.

Oder vielmehr sollte es wie folgt gelesen werden:

Vererben Sie weniger, verbinden Sie mehr.


225
2018-03-11 15:50



Nun, so viele gute Antworten, ich möchte mehr dazu hinzufügen. Dies wird helfen zu verstehen Extending v/s Implementing Thread.
Expands bindet zwei Klassendateien sehr eng zusammen und kann etwas ziemlich schwer mit Code umgehen.

Beide Ansätze machen die gleiche Arbeit, aber es gab einige Unterschiede.
Der häufigste Unterschied ist 

  1. Wenn Sie die Thread-Klasse erweitern, können Sie danach keine andere Klasse erweitern, die Sie benötigen. (Wie Sie wissen, erlaubt Java nicht das Erben von mehr als einer Klasse).
  2. Wenn Sie Runnable implementieren, können Sie einen Speicherplatz für Ihre Klasse speichern, um sie in Zukunft oder jetzt zu erweitern.

Aber eins bedeutender Unterschied zwischen der Implementierung von Runnable und Erweiterung Thread ist das
  by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

Das folgende Beispiel hilft Ihnen, klarer zu verstehen

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

Ausgabe des obigen Programms.

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

Im Runnable Interface-Ansatz wird nur eine Instanz einer Klasse erstellt und von verschiedenen Threads geteilt. Daher wird der Wert des Zählers für jeden einzelnen Thread-Zugriff erhöht.

Im Gegensatz zum Thread-Klassenansatz müssen Sie für jeden Thread-Zugriff eine separate Instanz erstellen. Daher wird für jede Klasseninstanz ein anderer Speicher zugewiesen, und jeder hat einen separaten Zähler, der Wert bleibt gleich, was bedeutet, dass kein Inkrement eintreten wird, da keiner der Objektreferenzen gleich ist.

Wann sollte Runnable verwendet werden?
Verwenden Sie die Runnable-Schnittstelle, wenn Sie aus der Threadgruppe auf dieselbe Ressource zugreifen möchten. Vermeiden Sie die Verwendung der Thread-Klasse hier, da die Erstellung mehrerer Objekte mehr Speicher beansprucht und zu einem hohen Leistungsaufwand führt.

Eine Klasse, die Runnable implementiert, ist kein Thread und nur eine Klasse. Damit ein Runnable zu einem Thread wird, müssen Sie eine Instanz von Thread erstellen und sich selbst als Ziel übergeben.

In den meisten Fällen sollte die Runnable-Schnittstelle verwendet werden, wenn Sie nur beabsichtigen, die Runnable-Schnittstelle zu überschreiben run() Methode und keine anderen Thread-Methoden. Dies ist wichtig, weil Klassen nicht unterklassifiziert werden sollten, außer der Programmierer beabsichtigt, das grundlegende Verhalten der Klasse zu modifizieren oder zu verbessern.

Wenn eine Superklasse erweitert werden muss, ist die Implementierung der Runnable-Schnittstelle geeigneter als die Verwendung der Thread-Klasse. Weil wir beim Implementieren der Runnable-Schnittstelle eine weitere Klasse erweitern können, um einen Thread zu erstellen.

Ich hoffe, das wird helfen!


184
2018-03-05 14:26



Eine Sache, von der ich überrascht bin, wurde noch nicht erwähnt Runnable macht Ihre Klasse flexibler.

Wenn du Thread erweiterst, wird die Aktion, die du tust, immer in einem Thread sein. Wenn Sie jedoch implementieren Runnable es muss nicht sein. Sie können es in einem Thread ausführen oder es an eine Art von Executor-Service übergeben oder es einfach als Aufgabe in einer Anwendung mit einem einzelnen Thread weiterleiten (möglicherweise zu einem späteren Zeitpunkt, aber innerhalb desselben Threads). Die Optionen sind viel offener, wenn Sie nur verwenden Runnable als wenn du dich an dich binden würdest Thread.


73
2018-02-12 14:51



Wenn Sie dann eine andere Klasse implementieren oder erweitern möchten Runnable Interface ist am besten, wenn Sie nicht möchten, dass eine andere Klasse dann erweitert oder implementiert wird Thread Klasse ist vorzuziehen

Der häufigste Unterschied ist

enter image description here

Wenn du extends Thread Klasse, danach kann man keine andere Klasse erweitern, die man benötigt. (Wie Sie wissen, erlaubt Java nicht das Erben von mehr als einer Klasse).

Wenn du implements Runnable, können Sie einen Platz für Ihre Klasse speichern, um jede andere Klasse in Zukunft oder jetzt zu erweitern.

  • Java unterstützt keine Mehrfachvererbung, was bedeutet, dass Sie nur eine Klasse in Java erweitern können. Sobald Sie die Thread-Klasse erweitert haben, haben Sie Ihre Chance verloren und können keine andere Klasse in Java erweitern oder erben.

  • In der objektorientierten Programmierung bedeutet das Erweitern einer Klasse im Allgemeinen das Hinzufügen neuer Funktionen, Modifizieren oder Verbessern von Verhalten. Wenn wir keine Änderungen an Thread vornehmen, verwenden Sie stattdessen die Runnable-Schnittstelle.

  • Die ausführbare Schnittstelle stellt eine Aufgabe dar, die entweder mit einem einfachen Thread oder einem Executor oder auf andere Weise ausgeführt werden kann. Die logische Trennung von Task als ausführbar als Thread ist eine gute Designentscheidung.

  • Aufgabe als Runnable zu trennen bedeutet, dass wir die Aufgabe wiederverwenden können und auch die Freiheit haben, sie auf verschiedene Weise auszuführen. da Sie einen Thread nicht neu starten können, wenn er abgeschlossen ist. erneut Runnable vs Thread für Aufgabe, Runnable ist Gewinner.

  • Der Java-Designer erkennt dies und deshalb akzeptieren Executoren Runnable als Task und sie haben einen Worker-Thread, der diese Aufgabe ausführt.

  • Das Erben aller Thread-Methoden ist zusätzlicher Overhead, nur um eine Aufgabe zu repräsentieren, die leicht mit Runnable erledigt werden kann.

Mit freundlicher Genehmigung von javarevisited.blogspot.com

Dies waren einige der bemerkenswerten Unterschiede zwischen Thread und Runnable in Java, wenn Sie weitere Unterschiede zu Thread vs Runnable kennen, dann teilen Sie es bitte über Kommentare. Ich persönlich benutze Runnable über Thread für dieses Szenario und empfiehlt, Runnable oder Callable Schnittstelle basierend auf Ihrer Anforderung zu verwenden.

Der wesentliche Unterschied ist jedoch.

Wenn du extends Thread Klasse erstellt jeder Ihrer Threads ein eindeutiges Objekt und assoziiert es damit. Wenn du implements Runnableteilt es dasselbe Objekt mit mehreren Threads.


65
2018-05-11 08:59



Eigentlich ist es nicht klug zu vergleichen Runnable und Thread miteinander.

Diese beiden haben eine Abhängigkeit und Beziehung in Multi-Threading genau wie Wheel and Engine Beziehung des Kraftfahrzeugs.

Ich würde sagen, es gibt nur einen Weg zum Multithreading mit zwei Schritten. Lass mich meinen Standpunkt klarstellen.

Lauffähig:
Bei der Implementierung interface Runnable es bedeutet, dass du etwas kreierst, was ist run able in einem anderen Thread. Wenn Sie nun etwas erstellen, das innerhalb eines Threads ausgeführt werden kann (das in einem Thread ausgeführt werden kann), bedeutet das nicht, einen Thread zu erstellen.
Also die Klasse MyRunnable ist nichts als eine gewöhnliche Klasse mit einem void run Methode. Und seine Objekte sind gewöhnliche Objekte mit nur einer Methode run was beim Aufruf normal ausgeführt wird. (es sei denn wir übergeben das Objekt in einem Thread).

Faden:
class ThreadIch würde sagen, eine ganz besondere Klasse mit der Fähigkeit, einen neuen Thread zu starten, der tatsächlich Multi-Threading durch seine ermöglicht start() Methode.

Warum nicht klug vergleichen?
Weil wir beide für Multi-Threading benötigen.

Für Multi-Threading brauchen wir zwei Dinge:

  • Etwas, das in einem Thread (Runnable) ausgeführt werden kann.
  • Etwas, das einen neuen Thread (Thread) starten kann.

So technisch und theoretisch sind beide notwendig, um einen Thread zu starten, wird man Lauf und ein Wille Lass es laufen (Mögen Wheel and Engine von Kraftfahrzeugen).

Deshalb können Sie einen Thread nicht mit starten MyRunnable Sie müssen es an eine Instanz von übergeben Thread.

Aber Es ist möglich, einen Thread nur mit zu erstellen und auszuführen class Thread weil Klasse Thread implementiert Runnable das wissen wir alle Thread ist auch ein Runnable Innerhalb.

Endlich Thread und Runnable sind einander für Multithreading nicht Konkurrenz oder Ersatz ergänzen.


61
2018-05-12 13:50



Sie sollten Runnable implementieren, aber wenn Sie mit Java 5 oder höher arbeiten, sollten Sie es nicht mit starten new Thread aber benutze ein ExecutorService stattdessen. Für Details siehe: Wie implementiert man einfaches Threading in Java?.


41
2018-02-12 14:41



Ich bin kein Experte, aber ich kann mir einen Grund vorstellen, Runnable anstelle von extend zu implementieren. Thread: Java unterstützt nur einzelne Vererbung, so dass Sie nur eine Klasse erweitern können.

Edit: Dies hieß ursprünglich "Implementieren einer Schnittstelle erfordert weniger Ressourcen." Außerdem müssen Sie eine neue Thread-Instanz erstellen, das ist also falsch.


31
2018-02-12 14:32



Ich würde sagen, dass es einen dritten Weg gibt:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

Vielleicht ist das ein bisschen von meiner starken Nutzung von Javascript und Actionscript 3 beeinflusst, aber auf diese Weise muss Ihre Klasse nicht eine ziemlich vage Schnittstelle implementieren Runnable.


19
2017-10-25 21:41



Mit der Veröffentlichung von Java 8 gibt es jetzt eine dritte Option.

Runnable ist ein funktionale Schnittstelle, was bedeutet, dass Instanzen davon mit Lambda-Ausdrücken oder Methodenreferenzen erstellt werden können.

Ihr Beispiel kann ersetzt werden mit:

new Thread(() -> { /* Code here */ }).start()

oder wenn du einen benutzen willst ExecutorService und eine Methodenreferenz:

executor.execute(runner::run)

Diese sind nicht nur viel kürzer als Ihre Beispiele, sondern haben auch viele der Vorteile, die in anderen Antworten auf die Verwendung angegeben sind Runnable Über ThreadB. Einzelverantwortung und die Verwendung von Kompositionen, da Sie nicht auf das Verhalten des Threads spezialisiert sind. Auf diese Weise vermeiden Sie auch das Erstellen einer zusätzlichen Klasse, wenn Sie nur a benötigen Runnable wie Sie es in Ihren Beispielen tun.


16
2017-07-29 11:24