Question "Implémente Runnable" par rapport à "extends Thread"


Depuis combien de temps j'ai passé avec des threads en Java, j'ai trouvé ces deux façons d'écrire des threads:

Avec implements Runnable:

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

Ou avec extends Thread:

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

Y a-t-il une différence significative dans ces deux blocs de code?


1794
2018-02-12 14:28


origine


Réponses:


Oui: outils Runnable est le moyen préféré de le faire, IMO. Vous ne spécialisez pas vraiment le comportement du fil. Tu lui donnes juste quelque chose à faire. Cela signifie composition est le philosophiquement "plus" moyen d'aller.

Dans pratique termes, cela signifie que vous pouvez mettre en œuvre Runnable et s'étendent à partir d'une autre classe aussi bien.


1446
2018-02-12 14:32



tl; dr: implémente Runnable, c'est mieux. Cependant, la mise en garde est importante

En général, je recommanderais d'utiliser quelque chose comme Runnable plutôt que Thread parce que cela vous permet de garder votre travail uniquement couplé avec votre choix de concurrence. Par exemple, si vous utilisez un Runnable et décider plus tard que cela ne nécessite pas en fait son propre Thread, vous pouvez simplement appeler threadA.run ().

Caveat: Par ici, je déconseille fortement l'utilisation de threads bruts. Je préfère de beaucoup l'utilisation de Callables et FutureTasks (Du javadoc: "Un calcul asynchrone annulable"). L'intégration des délais d'attente, l'annulation correcte et le regroupement de threads de la prise en charge de la simultanéité moderne sont tous beaucoup plus utiles pour moi que des piles de Threads bruts.

Suivre: Il y a un FutureTask constructeur Cela vous permet d'utiliser Runnables (si c'est ce que vous préférez) tout en bénéficiant des outils de simultanéité modernes. Pour citer le javadoc:

Si vous n'avez pas besoin d'un résultat particulier, pensez à utiliser les constructions du formulaire:

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

Donc, si nous remplaçons leur runnable avec votre threadA, nous obtenons ce qui suit:

new FutureTask<Object>(threadA, null)

Une autre option qui vous permet de rester proche de Runnables est un ThreadPoolExecutor. Vous pouvez utiliser le exécuter méthode pour passer dans un Runnable pour exécuter "la tâche donnée dans le futur."

Si vous souhaitez essayer d'utiliser un pool de threads, le fragment de code ci-dessus devrait ressembler à Executors.newCachedThreadPool () méthode d'usine):

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

494
2018-02-12 14:37



Morale de l'histoire:

Héritez uniquement si vous souhaitez remplacer un comportement.

Ou plutôt, il devrait être lu comme:

Hériter moins, interface plus.


225
2018-03-11 15:50



Eh bien tant de bonnes réponses, je veux en ajouter plus à ce sujet. Cela aidera à comprendre Extending v/s Implementing Thread.
Extends lie très étroitement deux fichiers de classe et peut rendre difficile la gestion du code.

Les deux approches font le même travail mais il y a eu quelques différences.
La différence la plus commune est 

  1. Lorsque vous étendez la classe Thread, vous ne pouvez plus étendre aucune autre classe requise. (Comme vous le savez, Java n'autorise pas l'héritage de plus d'une classe).
  2. Lorsque vous implémente Runnable, vous pouvez enregistrer un espace pour que votre classe puisse étendre n'importe quelle classe à l'avenir ou maintenant.

Cependant, un différence significative entre l'exécution de Runnable et étendre le fil est que
  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.

L'exemple suivant vous aide à comprendre plus clairement

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

Sortie du programme ci-dessus.

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

Dans l'approche d'interface Runnable, une seule instance d'une classe est en cours de création et elle a été partagée par différents threads. Ainsi, la valeur de compteur est incrémentée pour chaque accès au thread.

Alors que l'approche de classe Thread, vous devez créer une instance distincte pour chaque accès au thread. Par conséquent, une mémoire différente est allouée pour chaque instance de classe et chacune a un compteur séparé, la valeur reste la même, ce qui signifie qu'aucun incrément ne se produira car aucune référence d'objet n'est identique.

Quand utiliser Runnable?
Utilisez l'interface Runnable lorsque vous souhaitez accéder à la même ressource à partir du groupe de threads. Evitez d'utiliser la classe Thread ici, car la création de plusieurs objets consomme plus de mémoire et devient une grosse surcharge de performance.

Une classe qui implémente Runnable n'est pas un thread et juste une classe. Pour qu'un Runnable devienne un Thread, vous devez créer une instance de Thread et se faire passer pour la cible.

Dans la plupart des cas, l'interface Runnable doit être utilisée si vous prévoyez uniquement de remplacer le run() méthode et aucune autre méthode Thread. Ceci est important car les classes ne doivent pas être sous-classées à moins que le programmeur n'ait l'intention de modifier ou d'améliorer le comportement fondamental de la classe.

Lorsqu'il est nécessaire d'étendre une super-classe, l'implémentation de l'interface Runnable est plus appropriée que l'utilisation de la classe Thread. Parce que nous pouvons étendre une autre classe en implémentant l'interface Runnable pour créer un thread.

J'espère que cela aidera!


184
2018-03-05 14:26



Une chose que je suis surpris n'a pas encore été mentionné est que la mise en œuvre Runnable rend votre classe plus flexible.

Si vous étendez le fil, l'action que vous faites sera toujours dans un fil. Cependant, si vous implémentez Runnable ça ne doit pas être. Vous pouvez l'exécuter dans un thread, ou le passer à une sorte de service d'exécution, ou simplement le passer comme une tâche dans une seule application threadée (peut-être être exécuté plus tard, mais dans le même thread). Les options sont beaucoup plus ouvertes si vous utilisez juste Runnable que si vous vous liez à Thread.


73
2018-02-12 14:51



Si vous voulez implémenter ou étendre une autre classe alors Runnable l'interface est le plus préférable sinon sage si vous ne voulez pas d'autre classe à étendre ou mettre en œuvre alors Thread classe est préférable

La différence la plus commune est

enter image description here

Lorsque vous extends Thread classe, après que vous ne pouvez pas étendre toute autre classe que vous avez exigé. (Comme vous le savez, Java n'autorise pas l'héritage de plus d'une classe).

Lorsque vous implements Runnable, vous pouvez enregistrer un espace pour votre classe pour étendre n'importe quelle autre classe dans le futur ou maintenant.

  • Java ne prend pas en charge l'héritage multiple, ce qui signifie que vous ne pouvez étendre qu'une classe en Java. Une fois que vous avez étendu la classe Thread, vous avez perdu votre chance et vous ne pouvez pas étendre ou hériter d'une autre classe en Java.

  • Dans la programmation orientée objet, étendre une classe signifie généralement ajouter de nouvelles fonctionnalités, modifier ou améliorer les comportements. Si nous n'apportons aucune modification sur Thread, utilisez plutôt l'interface Runnable.

  • L'interface exécutable représente une Tâche qui peut être exécutée soit par un Thread simple ou des Executors, soit par tout autre moyen. La séparation si logique de la tâche comme exécutable que du fil est une bonne décision de conception.

  • La séparation des tâches en Runnable signifie que nous pouvons réutiliser la tâche et que nous avons également la liberté de l'exécuter de différentes manières. puisque vous ne pouvez pas redémarrer un thread une fois qu'il est terminé. encore Runnable vs Thread pour la tâche, Runnable est gagnant.

  • Le concepteur Java le reconnaît et c'est pourquoi les Executors acceptent Runnable comme une tâche et disposent d'un thread de travail qui exécute ces tâches.

  • L'héritage de toutes les méthodes Thread est une surcharge supplémentaire pour représenter une tâche, ce qui peut être fait facilement avec Runnable.

Courtoisie de javarevisited.blogspot.com

Il y avait quelques différences notables entre Thread et Runnable en Java, si vous connaissez d'autres différences sur Thread vs Runnable, merci de le partager via les commentaires. J'utilise personnellement Runnable over Thread pour ce scénario et recommande d'utiliser l'interface Runnable ou Callable en fonction de vos besoins.

Cependant, la différence significative est.

Lorsque vous extends Thread classe, chacun de vos thread crée un objet unique et s'associe avec lui. Lorsque vous implements Runnable, il partage le même objet avec plusieurs threads.


65
2018-05-11 08:59



En fait, il n'est pas sage de comparer Runnable et Thread avec l'un l'autre.

Ces deux ont une dépendance et une relation dans le multithread comme Wheel and Engine relation de véhicule à moteur.

Je dirais qu'il n'y a qu'une seule façon de multi-threading avec deux étapes. Laissez-moi faire mon point.

Exécutable:
En mettant en œuvre interface Runnable cela signifie que vous créez quelque chose qui est run able dans un fil différent. Maintenant, créer quelque chose qui peut tourner à l'intérieur d'un thread (exécutable dans un thread) ne signifie pas créer un Thread.
Donc la classe MyRunnable n'est rien d'autre qu'une classe ordinaire avec void run méthode. Et ses objets seront des objets ordinaires avec seulement une méthode run qui va s'exécuter normalement lorsqu'il est appelé. (sauf si nous passons l'objet dans un fil).

Fil:
class Thread, Je dirais une classe très spéciale avec la possibilité de démarrer un nouveau thread qui permet réellement multi-threading à travers son start() méthode.

Pourquoi pas sage de comparer?
Parce que nous avons besoin des deux pour le multi-threading.

Pour le multi-threading, nous avons besoin de deux choses:

  • Quelque chose qui peut fonctionner à l'intérieur d'un thread (Runnable).
  • Quelque chose qui peut commencer un nouveau fil (Thread).

Donc, techniquement et théoriquement, les deux sont nécessaires pour commencer un fil, on va courir et une volonté fais-le courir (Comme Wheel and Engine de véhicule à moteur).

Voilà pourquoi vous ne pouvez pas démarrer un fil avec MyRunnable vous devez le passer à une instance de Thread.

Mais il est possible de créer et d'exécuter un thread en utilisant uniquement class Thread parce que la classe Thread met en oeuvre Runnable donc nous savons tous Thread est également Runnable à l'intérieur.

finalement Thread et Runnable sont complémentaires les uns aux autres pour multithread pas concurrent ou remplacement.


61
2018-05-12 13:50



Vous devez implémenter Runnable, mais si vous utilisez Java 5 ou plus, vous ne devriez pas le démarrer avec new Thread mais utilisez un ExecutorService au lieu. Pour plus de détails, voir: Comment implémenter un thread simple en Java.


41
2018-02-12 14:41



Je ne suis pas un expert, mais je peux penser à une raison d'implémenter Runnable au lieu d'étendre Thread: Java ne prend en charge que l'héritage unique, donc vous ne pouvez étendre qu'une seule classe.

Edit: A l'origine, "Implémenter une interface nécessite moins de ressources". aussi, mais vous devez créer une nouvelle instance Thread de toute façon, donc c'était faux.


31
2018-02-12 14:32