t
t
t
t
t t   14) Les Threads multiples
tttt
t
carrea) Préface carreb) Avant-propos carre1) Introduction sur les &laqo; objets » carre2) Tout est &laqo; objet » carre3) Contrôle du flux du programme carre4) Initialization & Cleanup carre5) Cacher l'implémentation carre6) Réutiliser les classes carre7) Polymorphisme carre8) Interfaces & classes internes carre9) Stockage des objets carre10) Error Handling with Exceptions carre11) Le système d’E/S de Java carre12) Identification dynamique de type carre13) Création de fenêtres & d'Applets 14) Les &laqo; Threads » multiples carre15) Informatique distribuée carreA) Passage et retour d'objets carreB) L'Interface Java Natif (JNI) carreC) Conseils pour une programation stylée en Java carreD) Resources
Texte original t Traducteur : Cédric Babault
t
t
///
Ce chapitre contient 9 pages
1 2 3 4 5 6 7 8 9
    
t t t
t t t
t
t t t
In ColorBoxes2 an array of CBoxList is created and initialized to hold grid CBoxLists, each of which knows how long to sleep. An equal number of CBox2 objects is then added to each CBoxList, and each list is told to go( ), which starts its thread.
t Dans ColorBoxes2 un tableau de CBoxList est créé et initialisé pour contenir la grille de CBoxList [grid CBoxList], chacune d'elles sait combien de temps dormir. Un nombre identique d'objets CBox2 est alors ajouter à chaque CBoxList, et sur chaque liste est appelé go(),qui démarre ce thread.
t t t
CBox2 is similar to CBox: it paints itself with a randomly chosen color. But that’s all a CBox2 does. All of the threading has been moved into CBoxList.
t CBox2 est similaire à CBox: elle se paint avec une couleur choisie au hasard. Mais c'est tout ce qu'une CBox2 fait. Tout le threading a été déplacé dans CBoxList.
t t t
The CBoxList could also have inherited Thread and had a member object of type ArrayList. That design has the advantage that the add( ) and get( ) methods could then be given specific argument and return value types instead of generic Objects. (Their names could also be changed to something shorter.) However, the design used here seemed at first glance to require less code. In addition, it automatically retains all the other behaviors of an ArrayList. With all the casting and parentheses necessary for get( ), this might not be the case as your body of code grows.
t Le CBoxList pourrait aussi avoir hérité de Thread et avoir un objet membre de type ArrayList. Ce design a l'avantage que les méthodes add() et get() puissent avoir des arguments et un type de valeur de retour spécifiques au lieu de ceux de la classe générique Object. (Leurs noms pourraient aussi être changés en quelque chose de plus court.) Cependant, le design utilisé ici semble au premier coup d'œil nécessiter moins de code. En plus, on garde automatiquement tous les autres comportements d'un ArrayList. Avec tous les cast et parenthèses nécessaires pour get(), ça ne devrait pas être le cas dès que votre code central augmente.
t t t
As before, when you implement Runnable you don’t get all of the equipment that comes with Thread, so you have to create a new Thread and hand yourself to its constructor in order to have something to start( ), as you can see in the CBoxList constructor and in go( ). The run( ) method simply chooses a random element number within the list and calls nextColor( ) for that element to cause it to choose a new randomly selected color.
t Comme précédemment, quand vous implémentez Runnable vous ne disposez pas de tout l'équipement que vous avez avec Thread, donc vous devez créer un nouveau Thread et passer vous même à son constructeur pour avoir quelque chose à démarrer (par start()), comme vous pouvez le voir dans le constructeur de CBoxList et dans go(). La méthode run() choisit simplement un numéro d'élément au hasard dans la liste et appelle nextColor() pour cet élément ce qui provoque le sélection au hasard d'une nouvelle couleur.
t t t
Upon running this program, you see that it does indeed run faster and respond more quickly (for instance, when you interrupt it, it stops more quickly), and it doesn’t seem to bog down as much at higher grid sizes. Thus, a new factor is added into the threading equation: you must watch to see that you don’t have “too many threads” (whatever that turns out to mean for your particular program and platform—here, the slowdown in ColorBoxes appears to be caused by the fact that there’s only one thread that is responsible for all painting, and it gets bogged down by too many requests). If you have too many threads, you must try to use techniques like the one above to “balance” the number of threads in your program. If you see performance problems in a multithreaded program you now have a number of issues to examine:
t En exécutant ce programme, vous voyez qu'effectivement il tourne et répond plus vite (par exemple, quand vous l'interrompez, il s'arrête plus rapidement), et il ne semble pas ralentir autant pour de grandes tailles de grilles. Ainsi, un nouveau facteur est ajouter à l'équation du threading: vous devez regarder pour voir si vous n'avez pas « trop de threads » (quelqu'en soit la signification pour votre programme et plate-forme en particulier, le ralentissement dans ColorBoxes apparaît comme provenant du fait qu'il n'y a qu'un thread qui répond pour toutes les colorations, et qu'il est ralenti par trop de requêtes). Si vous avez trop de threads, vous devez essayez d'utiliser des techniques comme celle ci-dessus pour « équilibrer » le nombre de threads dans votre programme. Si vous voyez des problèmes de performances dans un programme multithread vous avez maintenant plusieurs solutions à examiner:
t t t
  1. Do you have enough calls to sleep( ), yield( ), and/or wait( )?
  2. Are calls to sleep( ) long enough?
  3. Are you running too many threads?
  4. Have you tried different platforms and JVMs?
t
  1. Avez vous assez d'appels à sleep(), yield(), et/ou wait()?
  2. Les appels à sleep() sont-ils assez longs?
  3. Faites vous tournez trop de threads?
  4. Avez vous essayé différentes plates-formes et JVMs?
t t t
Issues like this are one reason that multithreaded programming is often considered an art.
t Des questions comme celles-là sont la raison pour laquelle la programmation multithread est souvent considéré comme un art.
t t t

Summary

t

Résumé

t t t
It is vital to learn when to use multithreading and when to avoid it. The main reason to use it is to manage a number of tasks whose intermingling will make more efficient use of the computer (including the ability to transparently distribute the tasks across multiple CPUs) or be more convenient for the user. The classic example of resource balancing is using the CPU during I/O waits. The classic example of user convenience is monitoring a “stop” button during long downloads.
t Il est vital d'apprendre quand utiliser le multithreading et quand l'éviter. La principale raison pour l'utiliser est pour gérer un nombre de taches qui mélangées rendront plus efficace l'utilisation de l'ordinateur (y compris la possibilité de distribuer de façon transparente les tâches sur plusieurs CPUs) ou être plus pratique pour l'utilisateur. L'exemple classique de répartition de ressources est l'utilisation du CPU pendant les attentes d'entrées/sorties. L'exemple classique du coté pratique pour l'utilisateur est la surveillance d'un bouton « stop » pendant un long téléchargement.
t t t
The main drawbacks to multithreading are:
t Les principaux inconvénients du multithreading sont:
t t t
  1. Slowdown while waiting for shared resources
  2. Additional CPU overhead required to manage threads
  3. Unrewarded complexity, such as the silly idea of having a separate thread to update each element of an array
  4. Pathologies including starving, racing, and deadlock
t
  1. Ralentissement en attente de ressources partagées
  2. Du temp CPU supplémentaire nécessaire pour gérer les threads
  3. Complexité infructueuse, comme l'idée folle d'avoir un thread séparé pour mettre à jour chaque élément d'un tableau
  4. Pathologies incluant starving [=mourir de faim!?], racing, et inter-blocage [deadlock]
t t t
An additional advantage to threads is that they substitute “light” execution context switches (of the order of 100 instructions) for “heavy” process context switches (of the order of 1000s of instructions). Since all threads in a given process share the same memory space, a light context switch changes only program execution and local variables. On the other hand, a process change—the heavy context switch—must exchange the full memory space.
t Un avantage supplémentaire des threads est qu'ils substituent des contextes d'exécution « léger » (de l'ordre de 100 instructions) aux contextes d'exécutions lourds des processus (de l'ordre de 1000 instructions). Comme tous les threads d'un processus donné partage le même espace mémoire, un contexte léger ne change que l'exécution du programme et les variables locales. D'un autre coté, un changement de processus — le changement de contexte lourd —  doit échanger l'intégralité de l'espace mémoire.
t t t
Threading is like stepping into an entirely new world and learning a whole new programming language, or at least a new set of language concepts. With the appearance of thread support in most microcomputer operating systems, extensions for threads have also been appearing in programming languages or libraries. In all cases, thread programming (1) seems mysterious and requires a shift in the way you think about programming; and (2) looks similar to thread support in other languages, so when you understand threads, you understand a common tongue. And although support for threads can make Java seem like a more complicated language, don’t blame Java. Threads are tricky.
t Le threading c'est comme marcher dans un monde entièrement nouveau et apprendre un nouveau langage de programmation entier, ou au moins un nouveau jeu de concepts de langage. Avec l'apparition du support des threads dans beaucoup de systèmes d'exploitation de micro-ordinateurs, des extensions pour les threads sont aussi apparues dans les langages de programmations ou librairies. Dans tous les cas, la programmation de thread (1) semble mystérieuse et requiert un changement dans votre façon de penser la programmation; et (2) apparaît comme similaire au support de thread dans les autres langages, donc quand vous comprenez les threads, vous les comprenez dans une langue commune. Et bien que le support des threads puisse faire apparaître Java comme un langage plus compliqué, n'accuser pas Java. Les threads sont difficiles.
t t t
One of the biggest difficulties with threads occurs because more than one thread might be sharing a resource—such as the memory in an object—and you must make sure that multiple threads don’t try to read and change that resource at the same time. This requires judicious use of the synchronized keyword, which is a helpful tool but must be understood thoroughly because it can quietly introduce deadlock situations.
t Une des plus grande difficultés des threads se produit lorsque plus d'un thread partagent une ressource — comme la mémoire dans un objet — et que vous devez être sûr que plusieurs threads n'essayent pas de lire et changer cette ressource en même temps. Cela nécessite l'utilisation judicieuse du mot clé synchronized, qui est un outil bien utile mais qui doit être bien compris parce qu'il peut introduire silencieusement des situations d'inter-blocage.
t t t
In addition, there’s a certain art to the application of threads. Java is designed to allow you to create as many objects as you need to solve your problem—at least in theory. (Creating millions of objects for an engineering finite-element analysis, for example, might not be practical in Java.) However, it seems that there is an upper bound to the number of threads you’ll want to create, because at some point a large number of threads seems to become unwieldy. This critical point is not in the many thousands as it might be with objects, but rather in the low hundreds, sometimes less than 100. As you often create only a handful of threads to solve a problem, this is typically not much of a limit, yet in a more general design it becomes a constraint.
t En plus, il y a un certain art dans la mise en application des threads. Java est conçu pour résoudre vos problèmes — au moins en théorie. (Créer des millions d'objets pour une analyse d'un ensemble fini d'élément dans l'ingénierie, par exemple, devrait être faisable en Java). Toutefois, il semble qu'il y ai une borne haute au nombre de threads que vous voudrez créer, parce que à un certain point un grand nombre de threads semble devenir lours. Ce point critique n'est pas dans les milliers comme il devrait être avec les objets, mais plutôt à quelques centaines, quelquefois moins que 100. Comme vous créez souvent seulement une poignée de threads pour résoudre un problème, c'est typiquement pas vraiment une limite, bien que dans un design plus général cela devient une contrainte.
t t t
A significant nonintuitive issue in threading is that, because of thread scheduling, you can typically make your applications run faster by inserting calls to sleep( ) inside run( )’s main loop. This definitely makes it feel like an art, in particular when the longer delays seem to speed up performance. Of course, the reason this happens is that shorter delays can cause the end-of-sleep( ) scheduler interrupt to happen before the running thread is ready to go to sleep, forcing the scheduler to stop it and restart it later so it can finish what it was doing and then go to sleep. It takes extra thought to realize how messy things can get.
t Une importante conséquence non-évidente du threading est que, en raison de l'ordonnancement des threads, vous pouvez classiquement rendre vos applications plus rapides en insérant des appels à sleep() dans la boucle principale de run(). Cela fait définitivement ressembler ça à un art, en particulier quand la longueur du délai semble augmenter les performances. Bien sûr, la raison pour laquelle cela arrive est que des délais plus court peuvent causer la fin de sleep() de l'interruption du scheduler avant que le thread tournant soit prêt à passer au sleep, forçant le scheduler à l'arrêter et le redémarrer plus tard afin qu'il puisse finir ce qu'il était en train de faire puis de passer à sleep. Cela nécessite une réflexion supplémentaire pour réaliser quel désordre regne dans tout ça.
t t t
One thing you might notice missing in this chapter is an animation example, which is one of the most popular things to do with applets. However, a complete solution (with sound) to this problem comes with the Java JDK (available at java.sun.com) in the demo section. In addition, we can expect better animation support to become part of future versions of Java, while completely different non-Java, non-programming solutions to animation for the Web are appearing that will probably be superior to traditional approaches. For explanations about how Java animation works, see Core Java 2 by Horstmann & Cornell, Prentice-Hall, 1997. For more advanced discussions of threading, see Concurrent Programming in Java by Doug Lea, Addison-Wesley, 1997, or Java Threads by Oaks & Wong, O’Reilly, 1997.
t Une chose que vous devez notez comme manquant dans ce chapitre est un exemple d'animation, ce qui est une des chose les plus populaires faite avec des applets. Toutefois, une solution complète (avec du son) à ce problème vient est disponible avec le Java JDK (disponible sur java.sun.com) dans la section demo. En plus, nous pouvons nous attendre à un meilleur support d'animation comme partie des futures versions de Java, tandis que des solutions très différentes du Java, non programmables, pour les animations apparaissent sur le Web qui seront probablement supérieures aux approches traditionnelles. Pour des explications à propos du fonctionnement des animations Java, voyez Core Java 2 par Horstmann & Cornell, Prentice-Hall, 1997. Pour des discussions plus avancées sur le threading, voyez Concurrent Programming in Java de Doug Lea, Addison-Wesley, 1997, ou Java Threads de Oaks & Wong, O’Reilly, 1997.
t t t

Exercises

t

Exercices

t t t
Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for a small fee from www.BruceEckel.com.
t Les solutions des exercices sélectionnés peuvent être trouvées dan le document électronique The Thinking in Java Annotated Solution Guide, disponible pour une petite contribution sur www.BruceEckel.com.
t t t
  1. Inherit a class from Thread and override the run( ) method. Inside run( ), print a message, and then call sleep( ). Repeat this three times, then return from run( ). Put a start-up message in the constructor and override finalize( ) to print a shut-down message. Make a separate thread class that calls System.gc( ) and System.runFinalization( ) inside run( ), printing a message as it does so. Make several thread objects of both types and run them to see what happens.
  2. Modify Sharing2.java to add a synchronized block inside the run( ) method of TwoCounter instead of synchronizing the entire run( ) method.
  3. Create two Thread subclasses, one with a run( ) that starts up, captures the reference of the second Thread object and then calls wait( ). The other class’ run( ) should call notifyAll( ) for the first thread after some number of seconds have passed, so the first thread can print a message.
  4. In Counter5.java inside Ticker2, remove the yield( ) and explain the results. Replace the yield( ) with a sleep( ) and explain the results.
  5. In ThreadGroup1.java, replace the call to sys.suspend( ) with a call to wait( ) for the thread group, causing it to wait for two seconds. For this to work correctly you must acquire the lock for sys inside a synchronized block.
  6. Change Daemons.java so that main( ) has a sleep( ) instead of a readLine( ). Experiment with different sleep times to see what happens.
  7. In Chapter 8, locate the GreenhouseControls.java example, which consists of three files. In Event.java, the class Event is based on watching the time. Change Event so that it is a Thread, and change the rest of the design so that it works with this new Thread-based Event.
  8. Modify Exercise 7 so that the java.util.Timer class found in JDK 1.3 is used to run the system.
  9. Starting with SineWave.java from Chapter 13, create a program (an applet/application using the Console class) that draws an animated sine wave that appears to scrolls past the viewing window like an oscilloscope, driving the animation with a Thread. The speed of the animation should be controlled with a java.swing.JSlider control.
  10. Modify Exercise 9 so that multiple sine wave panels are created within the application. The number of sine wave panels should be controlled by HTML tags or command-line parameters.
  11. Modify Exercise 9 so that the java.swing.Timer class is used to drive the animation. Note the difference between this and java.util.Timer.
t
  1. Faites hériter une classe de Thread et redéfinissez la méthode run(). Dans run(), affichez un message, puis appelez sleep(). Répétez cela trois fois, puis sortez de run(). Placer un message de démarrage dans le constructeur et redéfinissez finalize() pour afficher un message d'arrêt. Faites une classe thread séparée qui appelle System.gc() et System.runFinalization() dans run(), affichant également un message. Faites plusieurs objets threads des deux types et exécutez les pour voir ce qui ce passe.
  2. Modifiez Sharing2.java pour ajouter un bloc synchronized dans la méthode run() de TwoCounter à la place de la synchronisation sur l'intégralité de la méthode run().
  3. Créez deux sous-classes de Thread une avec un run() qui démarre, capture la référence à un second objet Thread et appelle alors wait(). Le run() de l'autre classe devrait appeler notifyAll() pour le premier thread après qu'un certain nombre de secondes se soit écoulé, ainsi le premier thread peut afficher un message.
  4. Dans Ticker2 de Counter5.java, supprimez le yield() et expliquez les résultats. Remplacez le yield() avec un sleep() et expliquez les résultats.
  5. Dans ThreadGroup1.java, remplacez l'appel à sys.suspend() par un appel à wait() pour le bon groupe de thread, entraînant une attente de deux secondes. Pour que ça marche correctement vous devez acquérir le verrou pour sys dans un bloc synchronized.
  6. Changez Daemons.java pour que main() ait un sleep() à la place d'un readLine(). Expérimentez avec différents temps pour le sleep pour voir ce qui se passe.
  7. Dans le chapitre 8, localisez l'exemple GreenhouseControls.java, qui est constitués de trois fichiers. Dans Event.java, la classe Event est basée sur l'observation du temps. Changez Event pour qu'il soit un Thread, et changez le reste du design pour qu'il fonctionne avec le nouvel Event basé sur Thread.
  8. Modifiez l'exercice 7 pour que la classe java.util.Timer trouvé dans le JDK 1.3 soit utilisée pour faire tourner le système.
  9. En commençant avec SineWave.java du Chapitre 13, créez un programme (une applet/application utilisant la classe Console ) qui dessine un signal sinus animé qui apparaît en défilant sur la fenêtre comme un oscilloscope, dirigeant l'animation avec un Thread. La vitesse de l'animation pourra être controller avec un contrôle java.swing.JSlider.
  10. Modifiez l'exercice 9 afin que de multiple signaux sinus puissent être contrôlés par des tags HTML ou des paramètres de la ligne de commande.
  11. Modifiez l'exercice 9 afin que la classe java.swing.Timer soit utilisée pour diriger l'animation. Notez la différence entre celle-ci et java.util.Timer.
t t t
[70] Runnable was in Java 1.0, while inner classes were not introduced until Java 1.1, which may partially account for the existence of Runnable. Also, traditional multithreading architectures focused on a function to be run rather than an object. My preference is always to inherit from Thread if I can; it seems cleaner and more flexible to me.
t [70] Runnable était dans Java 1.0, tandis que les classes internes n'ont été introduites que dans Java 1.1, qui devait partiellement compter pour l'existence de Runnable. De plus, les architectures multithread traditionelles se basent sur une fonction à exécuter plutôt qu'un objet. Ma préférence est toujours d'hériter de Thread si possible; cela parait plus clair et plus flexible pour moi.
t t t
[71] The Java Programming Language, by Ken Arnold and James Gosling, Addison-Wesley 1996 pp 179.
[ Previous Chapter ] [ Short TOC ] [ Table of Contents ] [ Index ] [ Next Chapter ]
Last Update:04/24/2000
t [71] The Java Programming Language, de Ken Arnold et James Gosling, Addison-Wesley 1996 pp 179.
t t t
t t t
t t
\\\
    
t t t
t
     
Sommaire Le site de Bruce Eckel