openclassroom - thread.sleep java




"Implémente Runnable" par rapport à "extends Thread" (20)

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

Avec les 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?


  1. 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.
  2. 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 .
  3. Runnable interface Runnable représente une Task qui peut être exécutée soit par un Thread simple, soit par des Executors soit par tout autre moyen. Donc, la séparation logique de la Task tant que Runnable que Thread est une bonne décision de conception.
  4. 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 a terminé, Runnable vs Thread pour la tâche, Runnable est le gagnant.
  5. Java designer recognizes this and that's why Executors accept Runnable as Task and they have worker thread which executes those task.
  6. Inheriting all Thread methods are additional overhead just for representing a Task which can can be done easily with Runnable .

Avec la sortie de Java 8, il y a maintenant une troisième option.

Runnable est une interface fonctionnelle , ce qui signifie que des instances peuvent être créées avec des expressions lambda ou des références de méthode.

Votre exemple peut être remplacé par:

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

ou si vous voulez utiliser un ExecutorService et une référence de méthode:

executor.execute(runner::run)

Ceux-ci sont non seulement beaucoup plus courts que vos exemples, mais aussi avec beaucoup d'avantages indiqués dans d'autres réponses d'utiliser Runnable over Thread , comme la responsabilité unique et l'utilisation de la composition parce que vous ne spécialisez pas le comportement du thread. De cette façon, vous éviterez également de créer une classe supplémentaire si tout ce dont vous avez besoin est un Runnable comme vous le faites dans vos exemples.


En fait, il n'est pas sage de comparer Runnable et Thread entre eux.

Ces deux ont une dépendance et une relation dans le multi-threading tout comme la relation de Wheel and Engine de moteur 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:
Lors de l'implémentation de l' interface Runnable cela signifie que vous créez quelque chose qui run able dans un thread 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 une méthode d' void run . Et ses objets seront des objets ordinaires avec seulement une méthode qui s'exécutera normalement lorsqu'elle sera appelée. (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 active réellement le multi-threading à travers sa méthode start() .

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 tous les deux sont nécessaires pour commencer le fil, on courra et on le fera rouler (comme Wheel and Engine de véhicule automobile).

C'est pourquoi vous ne pouvez pas démarrer un thread avec MyRunnable vous devez le passer à une instance de Thread .

Mais il est possible de créer et d'exécuter un thread uniquement à l'aide de la class Thread car Class Thread implémente Runnable donc nous savons tous que Thread est également un Runnable intérieur.

Enfin Thread et Runnable se complètent l'un l'autre pour le multithreading pas le concurrent ou le remplacement.


Exécutable parce que:

  • Laisse plus de flexibilité pour l'implémentation Runnable pour étendre une autre classe
  • Sépare le code de l'exécution
  • Vous permet d'exécuter votre runnable à partir d'un pool de threads, du thread d'événement ou de toute autre manière dans le futur.

Même si vous n'en avez pas besoin maintenant, vous pouvez le faire à l'avenir. Comme il n'y a aucun avantage à Thread, Runnable est une meilleure solution.


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.


L'instanciation d'une interface donne une séparation plus nette entre votre code et l'implémentation des threads, donc je préférerais implémenter Runnable dans ce cas.


Oui: implémente 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 que la composition est la voie philosophique "plus pure" à suivre.

Concrètement, cela signifie que vous pouvez implémenter Runnable et étendre d'une autre classe.


Puisqu'il s'agit d'un sujet très populaire et que les bonnes réponses sont réparties de manière approfondie, j'ai estimé qu'il était justifié de compiler les bonnes réponses des autres dans une forme plus concise, de sorte que les nouveaux arrivants ont une vue d'ensemble facile:

  1. Vous étendez généralement une classe pour ajouter ou modifier des fonctionnalités. Donc, si vous ne voulez pas remplacer un comportement Thread , utilisez Runnable.

  2. Dans le même ordre d'idées, si vous n'avez pas besoin d' hériter des méthodes de thread, vous pouvez vous en passer en utilisant Runnable.

  3. Héritage simple : Si vous étendez Thread, vous ne pouvez pas l'étendre à partir d'une autre classe, donc si c'est ce que vous devez faire, vous devez utiliser Runnable.

  4. C'est une bonne conception de séparer la logique du domaine des moyens techniques, dans ce sens, il est préférable d'avoir une tâche Runnable isolant votre tâche de votre coureur .

  5. Vous pouvez exécuter le même objet Runnable plusieurs fois , mais un objet Thread ne peut être démarré qu'une seule fois. (Peut-être la raison pour laquelle les Executors acceptent les Runnables, mais pas les Threads.)

  6. Si vous développez votre tâche en Runnable, vous avez toute la flexibilité pour l'utiliser maintenant et dans le futur . Vous pouvez le faire fonctionner simultanément via Executors mais aussi via Thread. Et vous pouvez toujours l'utiliser / l'appeler de manière non simultanée dans le même thread, tout comme n'importe quel autre type / objet ordinaire.

  7. Cela facilite également la séparation des aspects de logique de tâche et de simultanéité dans vos tests unitaires .

  8. Si vous êtes intéressé par cette question, vous pourriez également être intéressé par la différence entre Callable et Runnable .


Tout le monde ici semble penser que la mise en œuvre de Runnable est la voie à suivre et je ne suis pas vraiment en désaccord avec eux, mais il y a aussi une raison de prolonger Thread à mon avis, en fait vous l'avez démontré dans votre code.

Si vous implémentez Runnable alors la classe qui implémente Runnable n'a aucun contrôle sur le nom du thread, c'est le code appelant qui peut définir le nom du thread, comme ceci:

new Thread(myRunnable,"WhateverNameiFeelLike");

mais si vous étendez Thread, vous pouvez gérer cela dans la classe elle-même (comme dans votre exemple, vous nommez le thread 'ThreadB'). Dans ce cas vous:

A) pourrait lui donner un nom plus utile à des fins de débogage

B) forcent que ce nom soit utilisé pour toutes les instances de cette classe (sauf si vous ignorez le fait qu'il s'agit d'un thread et faites ce qui précède avec lui comme s'il s'agissait d'un Runnable mais nous parlons de convention ici de toute façon ignore cette possibilité que je ressens).

Vous pouvez même, par exemple, prendre une trace de sa création et l'utiliser comme nom de thread. Cela peut sembler étrange, mais en fonction de la structure de votre code, il peut être très utile pour le débogage.

Cela peut sembler une petite chose mais où vous avez une application très complexe avec beaucoup de threads et tout d'un coup les choses 'ont cessé' (soit pour des raisons d'impasse ou peut-être à cause d'une faille dans un protocole réseau qui serait moins évidente - ou d'autres raisons sans fin) puis obtenir une pile de Java où tous les threads sont appelés 'Thread-1', 'Thread-2', 'Thread-3' n'est pas toujours très utile (cela dépend de la façon dont vos threads sont structuré et si vous pouvez dire utilement lequel est juste par leur trace de pile - pas toujours possible si vous utilisez des groupes de plusieurs threads qui exécutent tous le même code).

Cela dit, vous pouvez bien sûr aussi faire ce qui précède de manière générique en créant une extension de la classe thread qui définit son nom sur une trace de pile de son appel de création et l'utilise ensuite avec vos implémentations Runnable au lieu de la classe Thread java standard (voir ci-dessous) mais en plus de la trace de la pile, il pourrait y avoir plus d'informations spécifiques au contexte qui seraient utiles dans le nom de thread pour le débogage (une référence à l'une des nombreuses files d'attente). étendre Thread spécifiquement pour ce cas de sorte que vous pouvez avoir le compilateur vous obliger (ou d'autres utilisant vos bibliothèques) de transmettre certaines informations (par exemple la file d'attente / socket en question) pour l'utilisation dans le nom).

Voici un exemple de thread générique avec la trace de la pile appelante sous son nom:

public class DebuggableThread extends Thread {
    private static String getStackTrace(String name) {
        Throwable t= new Throwable("DebuggableThread-"+name);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        t.printStackTrace(ps);
        return os.toString();
    }

    public DebuggableThread(String name) {
        super(getStackTrace(name));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new Thread());
        System.out.println(new DebuggableThread("MainTest"));
    }
}

et voici un exemple de sortie comparant les deux noms:

Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
    at DebuggableThread.getStackTrace(DebuggableThread.java:6)
    at DebuggableThread.<init>(DebuggableThread.java:14)
    at DebuggableThread.main(DebuggableThread.java:19)
,5,main]

Une chose qui me surprend n'a pas encore été mentionnée est que l'implémentation de 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 ce n'est pas Runnable . 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 simplement Runnable que si vous vous liez à Thread .


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 car cela vous permet de garder votre travail uniquement couplé avec votre choix de concurrence. Par exemple, si vous utilisez un Runnable et décidez plus tard que cela ne nécessite pas son propre Thread , vous pouvez simplement appeler threadA.run ().

Mise en garde: Par ici, je déconseille fortement l'utilisation de threads bruts. Je préfère de FutureTasks l'utilisation de FutureTasks 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.

Suivi: il existe un constructeur FutureTask qui 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 par 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 la méthode execute pour passer dans Runnable afin d'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 à ceci (en utilisant la méthode d'usine Executors.newCachedThreadPool() ):

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

Adding my two cents here - Always whenever possible use implements Runnable . Below are two caveats on why you should not use extends Thread s

  1. Ideally you should never extend the Thread class; the Thread class should be made final . At least its methods like thread.getId() . See this discussion for a bug related to extending Thread s.

  2. Those who like to solve puzzles can see another side effect of extending Thread. The below code will print unreachable code when nobody is notifying them.

Please see http://pastebin.com/BjKNNs2G .

public class WaitPuzzle {

    public static void main(String[] args) throws InterruptedException {
        DoNothing doNothing = new DoNothing();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        Thread.sleep(100);
        doNothing.start();
        while(true) {
            Thread.sleep(10);
        }
    }


    static class WaitForever extends  Thread {

        private DoNothing doNothing;

        public WaitForever(DoNothing doNothing) {
            this.doNothing =  doNothing;
        }

        @Override
        public void run() {
            synchronized (doNothing) {
                try {
                    doNothing.wait(); // will wait forever here as nobody notifies here
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unreachable Code");
            }
        }
    }

    static class DoNothing extends Thread {

        @Override
        public void run() {
            System.out.println("Do Nothing ");
        }
    } 
}

Difference between Extending Thread and Implementing Runnable are:


Difference between Thread and runnable .If we are creating Thread using Thread class then Number of thread equal to number of object we created . If we are creating thread by implementing the runnable interface then we can use single object for creating multiple thread.So single object is shared by multiple Thread.So it will take less memory

So depending upon the requirement if our data is not senstive. So It can be shared between multiple Thread we can used Runnable interface.


If I am not wrong, it's more or less similar to

Quelle est la différence entre une interface et une classe abstraite?

extends establishes " Is A " relation & interface provides " Has a " capability.

Prefer implements Runnable :

  1. If you don't have to extend Thread class and modify Thread API default implementation
  2. If you are executing a fire and forget command
  3. If You are already extending another class

Prefer " extends Thread " :

  1. If you have to override any of these Thread methods as listed in oracle documentation page

Generally you don't need to override Thread behaviour. So implements Runnable is preferred for most of the times.

On a different note, using advanced ExecutorService or ThreadPoolExecutorService API provides more flexibility and control.

Have a look at this SE Question:

ExecutorService vs Casual Thread Spawner


Java does not support multiple inheritence so if you extends Thread class then no other class will be extended.

For Example: If you create an applet then it must extends Applet class so here the only way to create thread is by implementing Runnable interface


One reason you'd want to implement an interface rather than extend a base class is that you are already extending some other class. You can only extend one class, but you can implement any number of interfaces.

If you extend Thread, you're basically preventing your logic to be executed by any other thread than 'this'. If you only want some thread to execute your logic, it's better to just implement Runnable.


Separating the Thread class from the Runnable implementation also avoids potential synchronization problems between the thread and the run() method. A separate Runnable generally gives greater flexibility in the way that runnable code is referenced and executed.


This is discussed in Oracle's Defining and Starting a Thread tutorial:

Which of these idioms should you use? The first idiom, which employs a Runnable object, is more general, because the Runnable object can subclass a class other than Thread. The second idiom is easier to use in simple applications, but is limited by the fact that your task class must be a descendant of Thread. This lesson focuses on the first approach, which separates the Runnable task from the Thread object that executes the task. Not only is this approach more flexible, but it is applicable to the high-level thread management APIs covered later.

In other words, implementing Runnable will work in scenarios where your class extends a class other than Thread . Java does not support multiple inheritance. Also, extending Thread will not be possible when using some of the high-level thread management APIs. The only scenario where extending Thread is preferable is in a small application that won't be subject to updates in future. It is almost always better to implement Runnable as it is more flexible as your project grows. A design change won't have a major impact as you can implement many interfaces in java, but only extend one class.


Yes, If you call ThreadA call , then not need to call the start method and run method is call after call the ThreadA class only. But If use the ThreadB call then need to necessary the start thread for call run method. If you have any more help, reply me.







java-threads