Nun, so viele gute Antworten, ich möchte noch mehr dazu sagen. Dies wird helfen zu verstehen Extending v/s Implementing Thread
.
Extends bindet zwei Klassendateien sehr eng aneinander und kann zu ziemlich schwer zu handhabendem Code führen.
Beide Ansätze erfüllen die gleiche Aufgabe, aber es gibt einige Unterschiede.
Der häufigste Unterschied ist
- Wenn Sie die Klasse Thread erweitern, können Sie danach keine andere Klasse mehr erweitern, die Sie benötigen. (Wie Sie wissen, ist es in Java nicht möglich, mehr als eine Klasse zu erben).
- Wenn Sie Runnable implementieren, können Sie Platz für Ihre Klasse sparen, um jede andere Klasse in der Zukunft oder jetzt zu erweitern.
Allerdings ist eine erheblicher Unterschied zwischen der Implementierung von Runnable und der Erweiterung von Thread ist, dass
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 wird Ihnen helfen, die Situation besser 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 the 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
Beim Ansatz der Runnable-Schnittstelle wird nur eine Instanz einer Klasse erstellt, die von verschiedenen Threads gemeinsam genutzt wird. Daher wird der Wert des Zählers für jeden einzelnen Thread-Zugriff erhöht.
Beim Thread-Klassen-Ansatz hingegen müssen Sie für jeden Thread-Zugriff eine eigene Instanz erstellen. Daher wird für jede Klasseninstanz ein anderer Speicher zugewiesen und jeder hat einen separaten Zähler, dessen Wert gleich bleibt, was bedeutet, dass kein Inkrement erfolgt, da keine der Objektreferenzen gleich ist.
Wann sollte man Runnable verwenden?
Verwenden Sie die Schnittstelle Runnable, wenn Sie von einer Gruppe von Threads aus auf dieselben Ressourcen zugreifen wollen. Vermeiden Sie hier die Verwendung der Thread-Klasse, da die Erstellung mehrerer Objekte mehr Speicher verbraucht und zu einem großen Leistungs-Overhead 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 planen, die run()
Methode und keine anderen Thread-Methoden. Dies ist wichtig, weil Klassen nicht unterklassifiziert werden sollten, es sei denn, der Programmierer beabsichtigt, das grundlegende Verhalten der Klasse zu ändern oder zu verbessern.
Wenn es notwendig ist, eine Oberklasse zu erweitern, ist die Implementierung der Runnable-Schnittstelle besser geeignet als die Verwendung der Thread-Klasse. Denn wir können eine andere Klasse erweitern und gleichzeitig die Runnable-Schnittstelle implementieren, um einen Thread zu erstellen.
Ich hoffe, das wird helfen!
66 Stimmen
Vielen Dank für diese Frage, die Antworten haben eine Menge Missverständnisse, die ich hatte, aufgeklärt. Ich schaute in den richtigen Weg, um Java-Threads zu tun, bevor SO existierte und es gab eine Menge von Fehlinformationen / veraltete Informationen da draußen.
5 Stimmen
Gibt es einen Grund, warum Sie den Thread ( aber ich empfehle es nicht ), können Sie präventiv mit
interrupt()
. Auch hier handelt es sich um eine Idee, die im richtigen Fall nützlich sein könnte, aber ich empfehle sie nicht.0 Stimmen
Bitte lesen Sie auch die Antwort, die sehr gut erklärt ist: stackoverflow.com/q/5562720/285594
0 Stimmen
@bestsss, ich versuche herauszufinden, was Sie mit der Behandlung von interrupt() meinen könnten. Versuchen Sie, die Methode zu überschreiben?
0 Stimmen
@Bob, ja bob. Java macht das natürlich für
java.nio.channels.InterruptibleChannel
(s) Sie können einen Blick auf die Impl. von Thread.interrupt() werfen. Mit Hilfe der Hilfe voninterrupt()
caller ist eine Idee und ein nützlicher Ansatz, der wiederum nicht für Anfänger empfohlen wird.0 Stimmen
@Bob, es gibt noch eine andere Möglichkeit, nämlich die Erweiterung
java.nio.channels.spi.AbstractSelector
und außer Kraft setzenwakeup()
aber das ist eine viel zu schmutzige Art, den Fall zu beurteilen :)8 Stimmen
Ja, laut Code kann die Klasse Thread A jede Klasse erweitern, während die Klasse Thread B keine andere Klasse erweitern kann.
0 Stimmen
Sollte bei der Implementierung eines Callback über Runnable jetzt aussehen.
0 Stimmen
@RichieHH - das kommt darauf an. Rufen Sie nur zurück, wenn Sie einen Rückruf benötigen. Das heißt, wenn der laufende Code (die
Runnable
in OP) muss die Logik im Aufrufer ausführen.0 Stimmen
Lasse ich den Lauf leer? Wenn ich Funktionen verwende, laufen sie dann in einem anderen Thread?
0 Stimmen
Komposition ist im objektorientierten Design der Vererbung vorzuziehen
0 Stimmen
Verwenden Sie nicht direkt Thread, sollten Sie ExecutorService verwenden, die für bessere Tests gespottet werden kann
0 Stimmen
Erweitern Sie Thread, wenn Sie die Art und Weise, wie Thread sich verhält, VERÄNDERN wollen. Implementieren Sie runnable, wenn Sie einen anderen Thread erweitern müssen. Wenn Sie ein Objekt zwischen Threads teilen müssen, ist Runnable der richtige Weg, da Thread dies nicht erlaubt. Wenn keiner der beiden Fälle zutrifft, ist Runnable semantisch korrekter, obwohl dieser letzte Punkt nicht sehr wichtig ist, da jemand denken könnte, dass Sie das Verhalten von Thread geändert haben, wenn Sie ihn erweitern, obwohl Sie das nicht tun.