Vraag "Implementeert Runnable" versus "breidt Thread uit"


Vanaf welke tijd ik heb doorgebracht met threads in Java, heb ik deze twee manieren gevonden om threads te schrijven:

Met implements Runnable:

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

Of met extends Thread:

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

Is er een significant verschil in deze twee codeblokken?


1794
2018-02-12 14:28


oorsprong


antwoorden:


Ja: werktuigen Runnable is de aangewezen manier om het te doen, IMO. Je bent niet echt gespecialiseerd in het gedrag van de thread. Je geeft het gewoon iets om te rennen. Dat betekent samenstelling is de filosofisch "puurdere" manier om te gaan.

In praktisch voorwaarden betekent dit dat u kunt implementeren Runnable en ook uitbreiden van een andere klasse.


1446
2018-02-12 14:32



tl; dr: implementeert Runnable is beter. Het voorbehoud is echter belangrijk

Over het algemeen raad ik aan om zoiets te gebruiken Runnable liever dan Thread omdat het je toestaat je werk alleen losjes gekoppeld te houden aan je concurrencykeuze. Als u bijvoorbeeld een gebruikt Runnable en beslis later dat dit in feite niet zijn eigen vereist Thread, je kunt gewoon threadA.run () aanroepen.

Caveat: Hier in de buurt ontraad ik het gebruik van rauwe discussies ten zeerste. Ik geef de voorkeur aan het gebruik van Callables en FutureTasks (Uit de javadoc: "Een opzegbare asynchrone berekening"). De integratie van time-outs, de juiste annulering en de thread-pooling van de moderne concurrency-ondersteuning zijn allemaal veel nuttiger voor mij dan stapels rauwe discussies.

Opvolgen: er is een FutureTask bouwer waarmee u Runnables kunt gebruiken (als dat het is waar u het meest comfortabel mee bent) en toch het voordeel van de moderne concurrency-tools kunt benutten. Om de javadoc te citeren:

Als je een bepaald resultaat niet nodig hebt, overweeg dan om constructies van het formulier te gebruiken:

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

Dus als we hun vervangen runnable met uw threadA, we krijgen het volgende:

new FutureTask<Object>(threadA, null)

Een andere optie waarmee u dichter bij Runnables kunt blijven, is een ThreadPoolExecutor. U kunt de uitvoeren methode om in een loopbaantje door te geven om 'de gegeven taak ergens in de toekomst' uit te voeren.

Als u een threadpool wilt gebruiken, wordt het bovenstaande codefragment ongeveer het volgende (met behulp van de Executors.newCachedThreadPool () fabrieksmethode):

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

494
2018-02-12 14:37



Moraal van het verhaal:

Overname alleen als u bepaalde gedragingen wilt overschrijven.

Of beter gezegd, het moet gelezen worden als:

Overnemen minder, interface meer.


225
2018-03-11 15:50



Nou, zoveel goede antwoorden, ik wil hier meer aan toevoegen. Dit zal helpen om het te begrijpen Extending v/s Implementing Thread.
Extends bindt twee klassebestanden heel nauw en kan behoorlijk wat moeite kosten om met code om te gaan.

Beide benaderingen doen hetzelfde werk, maar er zijn enkele verschillen.
Het meest voorkomende verschil is 

  1. Wanneer u de Thread-klasse verlengt, kunt u daarna geen andere klasse uitbreiden die u nodig hebt. (Zoals u weet, staat Java niet toe dat meer dan één klasse wordt overgenomen).
  2. Wanneer u Runnable implementeert, kunt u een ruimte voor uw klas opslaan om een ​​andere klas in de toekomst of nu uit te breiden.

Echter, één Significant verschil tussen het implementeren van Runnable en het uitbreiden van Thread is dat
  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.

Het volgende voorbeeld helpt u om meer inzicht te krijgen

//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();
 }
}

Uitvoer van het bovenstaande programma.

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

In de interface-methode Runnable wordt slechts één exemplaar van een klasse gemaakt en gedeeld door verschillende threads. Dus de waarde van de teller wordt verhoogd voor elke thread-toegang.

Terwijl, Thread class aanpak, moet u een aparte instantie maken voor elke thread toegang. Daarom wordt voor elke klasse-instantie ander geheugen toegewezen en elk heeft een afzonderlijke teller, de waarde blijft hetzelfde, wat betekent dat er geen toename zal plaatsvinden omdat geen van de objectreferenties hetzelfde is.

Wanneer moet Runnable worden gebruikt?
Gebruik de interface Uitvoerbaar als u dezelfde resource wilt openen vanuit de discussiegroep. Vermijd het gebruik van Thread class hier, omdat het maken van meerdere objecten meer geheugen nodig heeft en het een grote prestatieoverhead wordt.

Een klasse die Runnable implementeert, is geen thread en slechts een klasse. Om een ​​Runnable een Thread te laten worden, moet je een instantie van Thread creëren en zichzelf als het doelwit doorgeven.

In de meeste gevallen moet de interface Runnable worden gebruikt als u alleen van plan bent om de run() methode en geen andere Thread-methoden. Dit is belangrijk omdat klassen niet moeten worden onderverdeeld, tenzij de programmeur van plan is om het fundamentele gedrag van de klas aan te passen of te verbeteren.

Wanneer het nodig is om een ​​superklasse uit te breiden, is het implementeren van de Runnable-interface meer geschikt dan het gebruik van de Thread-klasse. Omdat we een andere klasse kunnen uitbreiden terwijl de Runnable-interface wordt geïmplementeerd om een ​​thread te maken.

Ik hoop dat dit zal helpen!


184
2018-03-05 14:26



Een ding dat mij verbaast is nog niet genoemd, is dat het implementeren Runnable maakt je klas flexibeler.

Als je thread verlengt, zit de actie die je uitvoert altijd in een thread. Echter, als u implementeert Runnable het hoeft niet zo te zijn. Je kunt het in een thread uitvoeren, of doorgeven aan een of andere executor-service, of het gewoon doorgeven als een taak binnen een toepassing met één thread (misschien om op een later tijdstip te worden uitgevoerd, maar binnen dezelfde thread). De opties zijn veel meer open als je ze gewoon gebruikt Runnable dan als je jezelf verbindt Thread.


73
2018-02-12 14:51



Als je dan andere klassen wilt implementeren of uitbreiden Runnable interface heeft de meeste voorkeur op andere wijze als je niet wilt dat een andere klasse zich uitbreidt of implementeert Thread klasse heeft de voorkeur

Het meest voorkomende verschil is

enter image description here

Wanneer je extends Thread klas, daarna kun je geen andere klasse uitbreiden die je nodig hebt. (Zoals u weet, staat Java niet toe dat meer dan één klasse wordt overgenomen).

Wanneer je implements Runnable, je kunt een ruimte voor je klas sparen om een ​​andere klas in de toekomst of nu uit te breiden.

  • Java biedt geen ondersteuning voor meerdere overerving, wat betekent dat je slechts één klasse in Java kunt uitbreiden, dus zodra je de Thread-klasse hebt verlengd, heb je je kans verloren en kan je geen andere klasse in Java uitbreiden of erven.

  • Bij objectgeoriënteerd programmeren betekent een uitbreiding van een klasse in het algemeen het toevoegen van nieuwe functionaliteit, het aanpassen of verbeteren van gedrag. Als we geen wijzigingen aanbrengen in Thread, gebruikt u in plaats daarvan de Runnable-interface.

  • Een bruikbare interface vertegenwoordigt een taak die kan worden uitgevoerd door gewone threads of uitvoerders of op een andere manier. dus een logische scheiding van taken als Runnable than Thread is een goede ontwerpbeslissing.

  • Scheidingstaak als Runnable betekent dat we de taak opnieuw kunnen gebruiken en heeft ook de vrijheid om het op verschillende manieren uit te voeren. omdat je een Thread niet opnieuw kunt starten nadat deze is voltooid. opnieuw Runnable vs Thread voor taak, Runnable is winnaar.

  • Java-ontwerper herkent dit en daarom accepteren Executors Runnable als taak en hebben ze werkthread die deze taak uitvoert.

  • Het overnemen van alle Thread-methoden is extra overhead alleen voor het representeren van een taak die gemakkelijk kan worden gedaan met Runnable.

Met dank aan javarevisited.blogspot.com

Dit waren enkele van opmerkelijke verschillen tussen Thread en Runnable in Java. Als je nog andere verschillen kent op Thread vs Runnable, deel het dan via reacties. Ik gebruik persoonlijk Runnable over Thread voor dit scenario en raadt aan een Runnable of Callable-interface te gebruiken op basis van uw behoefte.

Het grote verschil is echter.

Wanneer je extends Thread klasse, elk van uw threads creëert een uniek object en associeert ermee. Wanneer je implements Runnable, het deelt hetzelfde object met meerdere threads.


65
2018-05-11 08:59



Eigenlijk is het niet verstandig om te vergelijken Runnable en Thread met elkaar.

Deze twee hebben een afhankelijkheid en relatie in multi-threading, net als Wheel and Engine relatie van motorvoertuig.

Ik zou zeggen dat er maar één manier is om multi-threading in twee stappen uit te voeren. Laat me mijn punt maken.

uitvoerbare:
Bij de implementatie interface Runnable het betekent dat je iets maakt dat is run able in een andere thread. Als u nu iets maakt dat in een thread kan worden uitgevoerd (dat binnen een thread kan worden uitgevoerd), betekent dit niet dat u een Thread moet maken.
Dus de klas MyRunnable is niets anders dan een gewone klas met een void run methode. En het zijn objecten die enkele gewone objecten zijn met alleen een methode run die normaal wordt uitgevoerd als deze wordt aangeroepen. (tenzij we het object in een thread doorgeven).

Draad:
class Thread, Zou ik zeggen Een heel speciale klasse met het vermogen om een ​​nieuwe Thread te starten die in feite multi-threading door de zijne mogelijk maakt start() methode.

Waarom niet verstandig om te vergelijken?
Omdat we ze allebei nodig hebben voor multi-threading.

Voor Multi-threading hebben we twee dingen nodig:

  • Iets dat in een thread kan worden uitgevoerd (Runnable).
  • Iets dat een nieuwe thread kan starten (Thread).

Dus technisch en theoretisch zijn ze allebei nodig om een ​​draad te beginnen, een wil rennen en een wil laat het rennen (Graag willen Wheel and Engine van motorvoertuigen).

Dat is waarom u geen thread kunt starten MyRunnable je moet het doorgeven aan een instantie van Thread.

Maar het is mogelijk om alleen een thread te maken en uit te voeren class Thread omdat Klasse Thread gereedschap Runnable dus we weten het allemaal Thread is ook een Runnable binnen.

Tenslotte Thread en Runnable zijn complementair aan elkaar voor multithreading, geen concurrent of vervanging.


61
2018-05-12 13:50



U moet Runnable implementeren, maar als u Java 5 of hoger gebruikt, moet u dit niet starten new Thread maar gebruik een ExecutorService in plaats daarvan. Voor details zie: Hoe eenvoudige threading in Java kan worden geïmplementeerd.


41
2018-02-12 14:41



Ik ben geen expert, maar ik kan een reden bedenken om Runnable te implementeren in plaats van Thread uit te breiden: Java ondersteunt alleen single inheritance, dus je kunt maar één klasse uitbreiden.

Bewerken: Dit zei oorspronkelijk: "Voor het implementeren van een interface zijn minder bronnen nodig." zo goed, maar je moet hoe dan ook een nieuwe Thread-instantie maken, dus dit was verkeerd.


31
2018-02-12 14:32