Penser en Java 2nde édition | - | Sommaire | Préface | Avant-propos | Chapitre : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Annexe : A B C D | Tables des matières | - | Thinking in Java |
La priorité d'un thread dit à l'ordonnanceur [scheduler] l'importance de ce thread. Si il y a un certain nombre de threads bloqués et en attente d'exécution, l'ordonnanceur exécutera celui avec la plus haute priorité en premier. Cependant, cela ne signifie pas que les threads avec des priorités plus faibles ne tourneront pas (en fait, vous ne pouvez pas avoir d'interblocage à cause des priorités). Les threads de priorités plus faibles ont juste tendance à tourner moins souvent.
Bien qu'il soit intéressant de connaître et de jouer avec les priorités, en pratique vous n'avez pratiquement jamais besoin de gérer les priorités par vous même. Donc soyez libre de passer le reste de cette session si les priorités ne vous intéressent pas.
Vous pouvez lire la priorité d'un thread avec getPriority() et la changer avec setPriority(). La forme des précédents exemples « counter » peut être utiliser pour montrer l'effet des changements de priorités. Dans cette applet vous verrez que les compteurs ralentissent quand les threads associés ont leurs priorités diminuées:
Ticker2 suit la forme établie plus tôt dans ce chapitre, mais il y a un JTextField supplémentaire pour afficher la priorité du thread et deux bouttons de plus pour incrémenter et décrémenter la priorité.
Vous pouvez également noter l'utilisation de yield(), qui rend volontairement la main à l'ordonnanceur. Sans cela le mécanisme de multithreading fonctionne encore, mais vous remarquerez qu'il tourne plus lentement (essayez de supprimer l'appel à yield() pour le voir). Vous pouvez aussi appeler sleep(), mais alors la vitesse de comptage sera controller par la durée du sleep() au lieu de la priorité.
Le init() dans Counter5 crée un tableau de dix Ticker2s; leurs bouttons et champs sont placés sur le formulaire par le constructeur de Ticker2. Counter5 ajoute des bouttons pour tout démarrer aussi bien que pour incrémenter et décrémenter la priorité maximum du groupe de thread. En plus, il y a des labels qui affichent les priorités maximum et minimum possibles pour un thread et un JTextField pour montrer la priorité maximum du groupe de thread. (La prochaine section décrira les groupes de threads.) Finalement, les priorités des groupes de threads parents sont aussi afficher comme labels.
Quand vous pressez un bouton « up » ou « down », la priorité du Tricker2 est rapportée et incrémenter ou décrémenter en conséquence.
Quand vous exécutez ce programme, vous noterez plusieurs choses. Tout d'abord, la priorité du groupe de thread est par défaut cinq. Même si vous décrémentez la priorité maximum en dessous de cinq avant de démarrer les threads (ou avant de les créer, ce qui nécessite un changement du code), chaque thread aura une priorité par défaut de cinq.
Le test simple est de prendre un compteur et de décrémenter sa priorité jusqu'à un, et observez qu'il compte beaucoup plus lentement. Mais maintenant essayez de l'incrémenter de nouveau. Vous pouvez le ramené à la priorité du groupe de thread, mais pas plus haut. Maintenant décrémentez la priorité du groupe de threads. Les priorités des threads restent inchangées, mais si vous essayez de les modifier dans un sens ou dans l'autre vous verrez qu'elles sauteront automatiquement à la priorité du groupe de thread. Les nouvelles threads auront également une priorité par défaut qui peut être plus haute que la priorité du groupe. (Ainsi la priorité du groupe n'est pas un moyen d'empêcher les nouveaux threads d'avoir des priorités plus hautes que celles existantes.)
Finalement, essayez d'incrémenter la priorité maximum du groupe. On ne peut pas le faire. Vous pouvez seulement réduire la priorité maximum d'un groupe de thread, pas l'augmenter.
Tous les threads appartiennent à un groupe de thread. Ce peut être soit le groupe de thread par défaut, soit un groupe de thread que vous spécifiez explicitement quand vous créez le thread. A la création, le thread est attaché à un groupe et ne peut pas en changer. Chaque application a au moins un thread qui appartient au groupe de thread système. Si vous créez plus de threads sans spécifier de groupe, ils appartiendront aussi au groupe de thread système.
Les groupes de threads doivent aussi appartenir à d'autres groupes de threads. Le groupe de thread auquel un nouveau appartient doit être spécifié dans le constructeur. Si vous créez un groupe de thread sans spécifier de groupe auquel le rattacher, il sera placer dans le groupe de thread système. Ainsi, tous les groupes de threads de votre application auront en fin de compte le groupe de thread système comme parent.
La raison de l'existence des groupes de threads est difficile à déterminer à partir de la littérature, qui tend à être confuse sur le sujet. Il est souvent cité des raisons de sécurités. D'après Arnold & Gosling,« Les threads d'un groupe peuvent modifier les autres threads du groupe, y compris ceux situés plus bas dans la hiérarchie. Un thread ne peut pas modifier les threads extérieurs à son propre groupe ou les groupes qu'il contient. » Il est difficile de savoir ce que « modifier » est supposé signifier ici. L'exemple suivant montre un thread dans un sous-groupe « feuille » modifier les priorités de tous les threads de son arbre de groupe de thread aussi bien qu'appeler une méthode pour tous les threads de son arbre.
Dans main(), plusieurs ThreadGroups sont créés, placés en feuilles des autres: x n'a pas d'autres arguments que son nom (une String), ainsi il est automatiquement placé dans le groupe de threads « système », tandis que y est sous x et z est sous y. Notez que l'initialisation se passe dans l'ordre textuel donc ce code est légal.
Deux threads sont créés et placés dans différents groupes de threads. TestThread1 n'a pas de méthode run() mais a une méthode f() qui modifie le thread et écrit quelque chose afin que vous puissiez voir qu'elle a été appelée. TestThread2 est une sous classe de TestThread1 et sa méthode run() est assez élaboré. Elle récupère d'abord le groupe de thread du thread courant, puis remonte deux niveaux dans l'arbre d'héritage en utilisant getParent(). (Ceci est étudié puisque j'ai intentionnellement placer l'objet TestThread2 deux niveaux plus bas dans la hiérarchie.) A ce point, un tableau de références sur Thread est créé en utilisant la méthode activeCount() pour demander combien de threads sont dans ce groupe de thread et tous les groupes fils. La méthode enumerate() place les références à toutes ces threads dans le tableau gAll, ensuite je me parcourt simplement dans la totalité du tableau en appelant la méthode f() pour chaque thread, ainsi qu'en modifiant la priorité. Ainsi, un thread dans un groupe de thread « feuille » modifie les threads dans les groupes de threads parents.
La méthode de déboguage list() affiche toutes l'information sur un groupe de thread sur la sortie standard ce qui aide beaucoup lorsqu'on examine le comportement d'un groupe de threads. Voici la sortie du programme:
java.lang.ThreadGroup[name=x,maxpri=10]
Thread[one,5,x]
java.lang.ThreadGroup[name=y,maxpri=10]
java.lang.ThreadGroup[name=z,maxpri=10]
Thread[two,5,z]
one f()
two f()
java.lang.ThreadGroup[name=x,maxpri=10]
Thread[one,1,x]
java.lang.ThreadGroup[name=y,maxpri=10]
java.lang.ThreadGroup[name=z,maxpri=10]
Thread[two,1,z]
Non seulement list() affiche le nom du ThreadGroup ou du Thread, mais elle affiche aussi le nom du groupe de thread et sa priorité maximum. Pour les threads, le nom de thread est également affiché, suivi par la priorité du thread et le groupe auquel il appartient. Notez que list() indente les threads et groupes de threads pour indiquer qu'ils sont enfant du groupe de threads non indenté.
Vous pouvez voir que f() est appelé par la méthode run() de TestThread2, il est donc évident que tous les threads d'un groupe sont vulnérables. Cependant, vous ne pouvez accéder seulement aux threads embranchés sur votre propre arbre du groupe de thread système, et peut-être que c'est ce que signifie « sûr. » Vous ne pouvez pas accéder à l'arbre du groupe de thread système d'un autre.
En dehors de l'aspect sécurité, une chose pour lesquelles les groupes de threads semble être utiles est le controle: vous pouvez effectuer certaines opérations sur un groupe de thread entier avec une seule commande. L'exemple suivant le démontre, et les restrictions sur les priorités avec les groupes de threads. Les numéros entre parenthèses donne une référence pour comparer la sortie.