CodeGym /Blog Java /Random-FR /Multithreading en Java
Auteur
Oleksandr Miadelets
Head of Developers Team at CodeGym

Multithreading en Java

Publié dans le groupe Random-FR
Salut! Tout d'abord, félicitations : vous avez atteint le sujet du multithreading en Java ! C'est une réalisation sérieuse - vous avez parcouru un long chemin. Mais préparez-vous : c'est l'un des sujets les plus difficiles du cours. Et ce n'est pas que nous utilisons des classes complexes ou beaucoup de méthodes ici : en fait, nous en utiliserons moins de vingt. C'est plus que vous aurez besoin de changer légèrement votre façon de penser. Auparavant, vos programmes étaient exécutés séquentiellement. Certaines lignes de code venaient après d'autres, certaines méthodes venaient après d'autres, et tout était fondamentalement clair. Tout d'abord, nous avons calculé quelque chose, puis affiché le résultat sur la console, puis le programme s'est terminé. Pour comprendre le multithreading, il vaut mieux penser en termes de parallélisme. Commençons par quelque chose d'assez simple : ) Imaginez que votre famille déménage d'une maison à une autre. Rassembler tous vos livres sera une partie importante du déménagement. Vous avez accumulé beaucoup de livres et vous devez les ranger dans des cartons. Actuellement, vous êtes le seul disponible. Maman prépare à manger, mon frère prépare des vêtements et ma sœur est allée au magasin. Seul, vous pouvez vous débrouiller d'une manière ou d'une autre. Tôt ou tard, vous terminerez la tâche vous-même, mais cela prendra beaucoup de temps. Cependant, votre sœur reviendra du magasin dans 20 minutes et elle n'a rien d'autre à faire. Elle peut donc vous rejoindre. La tâche n'a pas changé : mettre des livres dans des cartons. Mais il est exécuté deux fois plus vite. Pourquoi? Parce que le travail se fait en parallèle. Deux "threads" différents (vous et votre sœur) exécutent la même tâche simultanément. Et si rien ne change, alors il y aura un énorme décalage horaire par rapport à la situation où vous faites tout par vous-même. Si frère termine son travail bientôt, il peut vous aider et les choses iront encore plus vite.

Problèmes résolus par le multithreading

Le multithreading a en fait été inventé pour atteindre deux objectifs importants :
  1. Faire plusieurs choses en même temps.

    Dans l'exemple ci-dessus, différents threads (membres de la famille) ont effectué plusieurs actions en parallèle : ils ont lavé la vaisselle, sont allés au magasin et ont emballé des choses.

    Nous pouvons offrir un exemple plus étroitement lié à la programmation. Supposons que vous ayez un programme avec une interface utilisateur. Lorsque vous cliquez sur "Continuer" dans le programme, certains calculs doivent se produire et l'utilisateur doit voir l'écran suivant. Si ces actions étaient effectuées de manière séquentielle, le programme se bloquerait simplement après que l'utilisateur ait cliqué sur le bouton "Continuer". L'utilisateur verra l'écran avec le bouton "Continuer" jusqu'à ce que le programme effectue tous les calculs internes et atteigne la partie où l'interface utilisateur est actualisée.

    Eh bien, je suppose que nous allons attendre quelques minutes !

    Multithreading en Java : qu'est-ce que c'est, ses avantages et ses pièges courants - 3

    Ou nous pourrions retravailler notre programme, ou, comme disent les programmeurs, le « paralléliser ». Effectuons nos calculs sur un thread et dessinons l'interface utilisateur sur un autre. La plupart des ordinateurs ont suffisamment de ressources pour le faire. Si nous empruntons cette voie, le programme ne se bloquera pas et l'utilisateur se déplacera en douceur entre les écrans sans se soucier de ce qui se passe à l'intérieur. L'un n'interfère pas avec l'autre :)

  2. Effectuez des calculs plus rapidement.

    Tout est beaucoup plus simple ici. Si notre processeur a plusieurs cœurs, et la plupart des processeurs le font aujourd'hui, alors plusieurs cœurs peuvent gérer notre liste de tâches en parallèle. Évidemment, si nous devons effectuer 1000 tâches et que chacune prend une seconde, un cœur peut terminer la liste en 1000 secondes, deux cœurs en 500 secondes, trois en un peu plus de 333 secondes, etc.

Mais comme vous l'avez déjà lu dans cette leçon, les systèmes d'aujourd'hui sont très intelligents et, même sur un cœur de calcul, ils sont capables d'atteindre le parallélisme, ou plutôt le pseudo-parallélisme, où les tâches sont exécutées en alternance. Passons des généralités aux détails et apprenons à connaître la classe la plus importante de la bibliothèque multithreading Java - java.lang.Thread. Strictement parlant, les threads Java sont représentés par des instances de la classe Thread . Cela signifie que pour créer et exécuter 10 threads, vous avez besoin de 10 instances de cette classe. Écrivons l'exemple le plus simple :

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("I'm Thread! My name is " + getName());
   }
}
Pour créer et exécuter des threads, nous devons créer une classe, la faire hériter du java.lang . Thread et remplacez sa méthode run() . Cette dernière exigence est très importante. C'est dans la méthode run() que nous définissons la logique d'exécution de notre thread. Maintenant, si nous créons et exécutons une instance de MyFirstThread , la méthode run() affichera une ligne avec un nom : la méthode getName() affiche le nom 'system' du thread, qui est attribué automatiquement. Mais pourquoi parle-t-on timidement ? Créons-en un et découvrons-le !

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Sortie console : je suis Thread ! Je m'appelle Thread-2, je suis Thread ! Je m'appelle Thread-1, je suis Thread ! Je m'appelle Thread-0, je suis Thread ! Je m'appelle Thread-3, je suis Thread ! Je m'appelle Thread-6, je suis Thread ! Je m'appelle Thread-7, je suis Thread ! Je m'appelle Thread-4, je suis Thread ! Je m'appelle Thread-5, je suis Thread ! Je m'appelle Thread-9, je suis Thread ! Mon nom est Thread-8 Créons 10 threads ( objets MyFirstThread , qui héritent de Thread ) et démarrons-les en appelant la méthode start() sur chaque objet. Après avoir appelé la méthode start() , la logique de la méthode run() est exécutée. Remarque : les noms des threads ne sont pas dans l'ordre. C'est bizarre qu'ils n'aient pas été séquentiels :, Thread-1 , Thread-2 , etc. En l'occurrence, c'est un exemple d'un moment où la pensée « séquentielle » ne convient pas. Le problème est que nous n'avons fourni que des commandes pour créer et exécuter 10 threads. Le planificateur de threads, un mécanisme spécial du système d'exploitation, décide de leur ordre d'exécution. Sa conception précise et sa stratégie de prise de décision sont des sujets de discussion approfondie dans lesquels nous ne plongerons pas pour le moment. La principale chose à retenir est que le programmeur ne peut pas contrôler l'ordre d'exécution des threads. Pour comprendre la gravité de la situation, essayez d'exécuter la méthode main() dans l'exemple ci-dessus plusieurs fois. Sortie de la console lors de la deuxième exécution : Je suis Thread ! Je m'appelle Thread-0, je suis Thread ! Je m'appelle Thread-4, je suis Thread ! Je m'appelle Thread-3, je suis Thread ! Je m'appelle Thread-2, je suis Thread ! Je m'appelle Thread-1, je suis Thread ! Je m'appelle Thread-5, je suis Thread ! Je m'appelle Thread-6, je suis Thread ! Je m'appelle Thread-8, je suis Thread ! Je m'appelle Thread-9, je suis Thread ! Mon nom est la sortie de la console Thread-7 de la troisième exécution : je suis Thread ! Je m'appelle Thread-0, je suis Thread ! Je m'appelle Thread-3, je suis Thread ! Je m'appelle Thread-1, je suis Thread ! Je m'appelle Thread-2, je suis Thread ! Je m'appelle Thread-6, je suis Thread ! Je m'appelle Thread-4, je suis Thread ! Je m'appelle Thread-9, je suis Thread ! Je m'appelle Thread-5, je suis Thread ! Je m'appelle Thread-7, je suis Thread ! Je m'appelle Thread-8

Problèmes créés par le multithreading

Dans notre exemple avec des livres, vous avez vu que le multithreading résout des tâches très importantes et peut rendre nos programmes plus rapides. Souvent plusieurs fois plus rapide. Mais le multithreading est considéré comme un sujet difficile. En effet, s'il est mal utilisé, il crée des problèmes au lieu de les résoudre. Quand je dis « crée des problèmes », je ne veux pas dire dans un sens abstrait. Le multithreading peut créer deux problèmes spécifiques : les blocages et les conditions de concurrence. Le blocage est une situation où plusieurs threads attendent des ressources détenues les unes par les autres, et aucun d'entre eux ne peut continuer à s'exécuter. Nous en reparlerons dans les leçons suivantes. L'exemple suivant suffira pour l'instant : Multithreading en Java : qu'est-ce que c'est, ses avantages et ses pièges courants - 4Imaginez que Thread-1 interagisse avec un Object-1, et que Thread-2 interagisse avec Object-2. De plus, le programme est écrit de telle sorte que :
  1. Thread-1 arrête d'interagir avec Object-1 et passe à Object-2 dès que Thread-2 arrête d'interagir avec Object-2 et passe à Object-1.
  2. Thread-2 cesse d'interagir avec Object-2 et passe à Object-1 dès que Thread-1 cesse d'interagir avec Object-1 et passe à Object-2.
Même sans une compréhension approfondie du multithreading, vous pouvez facilement voir que rien ne se passera. Les fils ne changeront jamais de place et s'attendront pour toujours. L'erreur semble évidente, mais en réalité elle ne l'est pas. Vous pouvez facilement le faire dans un programme. Nous examinerons des exemples de code provoquant un blocage dans les leçons suivantes. Soit dit en passant, Quora a un excellent exemple concret qui explique ce qu'est une impasseest. « Dans certains États de l'Inde, ils ne vous vendront pas de terres agricoles à moins que vous ne soyez un agriculteur enregistré. Cependant, ils ne vous enregistreront pas en tant qu'agriculteur si vous ne possédez pas de terres agricoles ». Super! Que pouvons-nous dire ? ! :) Parlons maintenant des conditions de course. Une condition de concurrence est une erreur de conception dans un système ou une application multithread, où le fonctionnement du système ou de l'application dépend de l'ordre dans lequel les parties du code sont exécutées. Rappelez-vous, notre exemple où nous avons commencé les threads :

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Imaginez maintenant que le programme est chargé de faire fonctionner un robot qui cuisine des aliments ! Thread-0 sort les œufs du réfrigérateur. Thread-1 allume le poêle. Thread-2 prend une casserole et la pose sur la cuisinière. Thread-3 allume le poêle. Thread-4 verse de l'huile dans la casserole. Thread-5 casse les œufs et les verse dans la casserole. Thread-6 jette les coquilles d'œufs dans la poubelle. Thread-7 supprime les œufs cuits du brûleur. Thread-8 place les œufs cuits dans une assiette. Thread-9 lave la vaisselle. Regardez les résultats de notre programme : Thread exécuté : Thread-0 Thread exécuté : Thread-2 Thread exécuté Thread-1 Thread exécuté : Thread-4 Thread exécuté : Thread-9 Thread exécuté : Thread-5 Thread exécuté : Thread-8 Thread exécuté : Thread-7 Thread exécuté : Thread-3 Est-ce une routine comique ? :) Et tout cela parce que le travail de notre programme dépend de l'ordre d'exécution des threads. À la moindre violation de la séquence requise, notre cuisine se transforme en enfer et un robot fou détruit tout ce qui l'entoure. C'est également un problème courant dans la programmation multithread. Vous en entendrez parler plus d'une fois. Pour conclure cette leçon, j'aimerais recommander un livre sur le multithreading. Le multithreading en Java : qu'est-ce que c'est, ses avantages et ses pièges courants - 6'Java Concurrency in Practice' a été écrit en 2006, mais n'a pas perdu de sa pertinence. Il est dédié à la programmation Java multithread - des bases aux erreurs et anti-modèles les plus courants. Si vous décidez un jour de devenir un gourou du multithreading, ce livre est une lecture incontournable. A bientôt dans les prochains cours ! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION