t
t
t
t
t t 14) Les Threads multiples
tttt
14) Les « Threads » multiples
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

Priorities

t

Priorités

t t t
The priority of a thread tells the scheduler how important this thread is. If there are a number of threads blocked and waiting to be run, the scheduler will run the one with the highest priority first. However, this doesn’t mean that threads with lower priority don’t get run (that is, you can’t get deadlocked because of priorities). Lower priority threads just tend to run less often. t 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.
t t t
Although priorities are interesting to know about and to play with, in practice you almost never need to set priorities yourself. So feel free to skip the rest of this section if priorities aren’t interesting to you. t 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.
t t t

Reading and setting priorities

t

Lire et changer les priorités

t t t
You can read the priority of a thread with getPriority( ) and change it with setPriority( ). The form of the prior “counter” examples can be used to show the effect of changing the priorities. In this applet you’ll see that the counters slow down as the associated threads have their priorities lowered: t 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:
t t t
//: c14:Counter5.java
// Adjusting the priorities of threads.
// <applet code=Counter5 width=450 height=600>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

class Ticker2 extends Thread {
  private JButton
    b = new JButton("Toggle"),
    incPriority = new JButton("up"),
    decPriority = new JButton("down");
  private JTextField
    t = new JTextField(10),
    pr = new JTextField(3); // Display priority
  private int count = 0;
  private boolean runFlag = true;
  public Ticker2(Container c) {
    b.addActionListener(new ToggleL());
    incPriority.addActionListener(new UpL());
    decPriority.addActionListener(new DownL());
    JPanel p = new JPanel();
    p.add(t);
    p.add(pr);
    p.add(b);
    p.add(incPriority);
    p.add(decPriority);
    c.add(p);
  }
  class ToggleL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  class UpL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() + 1;
      if(newPriority > Thread.MAX_PRIORITY)
        newPriority = Thread.MAX_PRIORITY;
      setPriority(newPriority);
    }
  }
  class DownL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() - 1;
      if(newPriority < Thread.MIN_PRIORITY)
        newPriority = Thread.MIN_PRIORITY;
      setPriority(newPriority);
    }
  }
  public void run() {
    while (true) {
      if(runFlag) {
        t.setText(Integer.toString(count++));
        pr.setText(
          Integer.toString(getPriority()));
      }
      yield();
    }
  }
}

public class Counter5 extends JApplet {
  private JButton
    start = new JButton("Start"),
    upMax = new JButton("Inc Max Priority"),
    downMax = new JButton("Dec Max Priority");
  private boolean started = false;
  private static final int SIZE = 10;
  private Ticker2[] s = new Ticker2[SIZE];
  private JTextField mp = new JTextField(3);
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    for(int i = 0; i < s.length; i++)
      s[i] = new Ticker2(cp);
    cp.add(new JLabel(
      "MAX_PRIORITY = " + Thread.MAX_PRIORITY));
    cp.add(new JLabel("MIN_PRIORITY = "
      + Thread.MIN_PRIORITY));
    cp.add(new JLabel("Group Max Priority = "));
    cp.add(mp);
    cp.add(start);
    cp.add(upMax);
    cp.add(downMax);
    start.addActionListener(new StartL());
    upMax.addActionListener(new UpMaxL());
    downMax.addActionListener(new DownMaxL());
    showMaxPriority();
    // Recursively display parent thread groups:
    ThreadGroup parent =
      s[0].getThreadGroup().getParent();
    while(parent != null) {
      cp.add(new Label(
        "Parent threadgroup max priority = "
        + parent.getMaxPriority()));
      parent = parent.getParent();
    }
  }
  public void showMaxPriority() {
    mp.setText(Integer.toString(
      s[0].getThreadGroup().getMaxPriority()));
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(!started) {
        started = true;
        for(int i = 0; i < s.length; i++)
          s[i].start();
      }
    }
  }
  class UpMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(++maxp > Thread.MAX_PRIORITY)
        maxp = Thread.MAX_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  class DownMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(--maxp < Thread.MIN_PRIORITY)
        maxp = Thread.MIN_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  public static void main(String[] args) {
    Console.run(new Counter5(), 450, 600);
  }
} ///:~
t
//: c14:Counter5.java
// Ajuster les priorités des threads.
// <applet code=Counter5 width=450 height=600>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

class Ticker2 extends Thread {
  private JButton
    b = new JButton("Toggle"),
    incPriority = new JButton("up"),
    decPriority = new JButton("down");
  private JTextField
    t = new JTextField(10),
    pr = new JTextField(3); // Affiche la priorité
  private int count = 0;
  private boolean runFlag = true;
  public Ticker2(Container c) {
    b.addActionListener(new ToggleL());
    incPriority.addActionListener(new UpL());
    decPriority.addActionListener(new DownL());
    JPanel p = new JPanel();
    p.add(t);
    p.add(pr);
    p.add(b);
    p.add(incPriority);
    p.add(decPriority);
    c.add(p);
  }
  class ToggleL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  class UpL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() + 1;
      if(newPriority > Thread.MAX_PRIORITY)
        newPriority = Thread.MAX_PRIORITY;
      setPriority(newPriority);
    }
  }
  class DownL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() - 1;
      if(newPriority < Thread.MIN_PRIORITY)
        newPriority = Thread.MIN_PRIORITY;
      setPriority(newPriority);
    }
  }
  public void run() {
    while (true) {
      if(runFlag) {
        t.setText(Integer.toString(count++));
        pr.setText(
          Integer.toString(getPriority()));
      }
      yield();
    }
  }
}

public class Counter5 extends JApplet {
  private JButton
    start = new JButton("Start"),
    upMax = new JButton("#004488">"Inc Max Priority"),
    downMax = new JButton("#004488">"Dec Max Priority");
  private boolean started = false;
  private static final int SIZE = 10;
  private Ticker2[] s = new Ticker2[SIZE];
  private JTextField mp = new JTextField(3);
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    for(int i = 0; i < s.length; i++)
      s[i] = new Ticker2(cp);
    cp.add(new JLabel(
      "MAX_PRIORITY = " + Thread.MAX_PRIORITY));
    cp.add(new JLabel("MIN_PRIORITY = "
      + Thread.MIN_PRIORITY));
    cp.add(new JLabel("#004488">"Group Max Priority = "));
    cp.add(mp);
    cp.add(start);
    cp.add(upMax);
    cp.add(downMax);
    start.addActionListener(new StartL());
    upMax.addActionListener(new UpMaxL());
    downMax.addActionListener(new DownMaxL());
    showMaxPriority();
    // Affiche récursivement les groupes de thread parents:
    ThreadGroup parent =
      s[0].getThreadGroup().getParent();
    while(parent != null) {
      cp.add(new Label(
        "Parent threadgroup max priority = "
        + parent.getMaxPriority()));
      parent = parent.getParent();
    }
  }
  public void showMaxPriority() {
    mp.setText(Integer.toString(
      s[0].getThreadGroup().getMaxPriority()));
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(!started) {
        started = true;
        for(int i = 0; i < s.length; i++)
          s[i].start();
      }
    }
  }
  class UpMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(++maxp > Thread.MAX_PRIORITY)
        maxp = Thread.MAX_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  class DownMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(--maxp < Thread.MIN_PRIORITY)
        maxp = Thread.MIN_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  public static void main(String[] args) {
    Console.run(new Counter5(), 450, 600);
  }
} ///:~
t t t
Ticker2 follows the form established earlier in this chapter, but there’s an extra JTextField for displaying the priority of the thread and two more buttons for incrementing and decrementing the priority. t 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é.
t t t
Also notice the use of yield( ), which voluntarily hands control back to the scheduler. Without this the multithreading mechanism still works, but you’ll notice it runs slowly (try removing the call to yield( ) to see this). You could also call sleep( ), but then the rate of counting would be controlled by the sleep( ) duration instead of the priority. t 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é.
t t t
The init( ) in Counter5 creates an array of ten Ticker2s; their buttons and fields are placed on the form by the Ticker2 constructor. Counter5 adds buttons to start everything up as well as increment and decrement the maximum priority of the thread group. In addition, there are labels that display the maximum and minimum priorities possible for a thread and a JTextField to show the thread group’s maximum priority. (The next section will describe thread groups.) Finally, the priorities of the parent thread groups are also displayed as labels. t 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.
t t t
When you press an “up” or “down” button, that Ticker2’s priority is fetched and incremented or decremented accordingly. t 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.
t t t
When you run this program, you’ll notice several things. First of all, the thread group’s default priority is five. Even if you decrement the maximum priority below five before starting the threads (or before creating the threads, which requires a code change), each thread will have a default priority of five. t 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.
t t t
The simple test is to take one counter and decrement its priority to one, and observe that it counts much slower. But now try to increment it again. You can get it back up to the thread group’s priority, but no higher. Now decrement the thread group’s priority a couple of times. The thread priorities are unchanged, but if you try to modify them either up or down you’ll see that they’ll automatically pop to the priority of the thread group. Also, new threads will still be given a default priority, even if that’s higher than the group priority. (Thus the group priority is not a way to prevent new threads from having higher priorities than existing ones.) t 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.)
t t t
Finally, try to increment the group maximum priority. It can’t be done. You can only reduce thread group maximum priorities, not increase them. t 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.
t t t

Thread groups

t

Les groupes de threads

t t t
All threads belong to a thread group. This can be either the default thread group or a group you explicitly specify when you create the thread. At creation, the thread is bound to a group and cannot change to a different group. Each application has at least one thread that belongs to the system thread group. If you create more threads without specifying a group, they will also belong to the system thread group. t 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.
t t t
Thread groups must also belong to other thread groups. The thread group that a new one belongs to must be specified in the constructor. If you create a thread group without specifying a thread group for it to belong to, it will be placed under the system thread group. Thus, all thread groups in your application will ultimately have the system thread group as the parent. t 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.
t t t
The reason for the existence of thread groups is hard to determine from the literature, which tends to be confusing on this subject. It’s often cited as “security reasons.” According to Arnold & Gosling,[71] “Threads within a thread group can modify the other threads in the group, including any farther down the hierarchy. A thread cannot modify threads outside of its own group or contained groups.” It’s hard to know what “modify” is supposed to mean here. The following example shows a thread in a “leaf” subgroup modifying the priorities of all the threads in its tree of thread groups as well as calling a method for all the threads in its tree. t 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.
t t t
//: c14:TestAccess.java
// How threads can access other threads
// in a parent thread group.

public class TestAccess {
  public static void main(String[] args) {
    ThreadGroup
      x = new ThreadGroup("x"),
      y = new ThreadGroup(x, "y"),
      z = new ThreadGroup(y, "z");
    Thread
      one = new TestThread1(x, "one"),
      two = new TestThread2(z, "two");
  }
}

class TestThread1 extends Thread {
  private int i;
  TestThread1(ThreadGroup g, String name) {
    super(g, name);
  }
  void f() {
    i++; // modify this thread
    System.out.println(getName() + " f()");
  }
}

class TestThread2 extends TestThread1 {
  TestThread2(ThreadGroup g, String name) {
    super(g, name);
    start();
  }
  public void run() {
    ThreadGroup g =
      getThreadGroup().getParent().getParent();
    g.list();
    Thread[] gAll = new Thread[g.activeCount()];
    g.enumerate(gAll);
    for(int i = 0; i < gAll.length; i++) {
      gAll[i].setPriority(Thread.MIN_PRIORITY);
      ((TestThread1)gAll[i]).f();
    }
    g.list();
  }
} ///:~
t
//: c14:TestAccess.java
// Comment les threads peuvent accéder aux
// autres threads dans un groupe de threads parent.

public class TestAccess {
  public static void main(String[] args) {
    ThreadGroup
      x = new ThreadGroup("x"),
      y = new ThreadGroup(x, "y"),
      z = new ThreadGroup(y, "z");
    Thread
      one = new TestThread1(x, "one"),
      two = new TestThread2(z, "two");
  }
}

class TestThread1 extends Thread {
  private int i;
  TestThread1(ThreadGroup g, String name) {
    super(g, name);
  }
  void f() {
    i++; // modifie ce thread
    System.out.println(getName() + " f()");
  }
}

class TestThread2 extends TestThread1 {
  TestThread2(ThreadGroup g, String name) {
    super(g, name);
    start();
  }
  public void run() {
    ThreadGroup g =
      getThreadGroup().getParent().getParent();
    g.list();
    Thread[] gAll = new Thread[g.activeCount()];
    g.enumerate(gAll);
    for(int i = 0; i < gAll.length; i++) {
      gAll[i].setPriority(Thread.MIN_PRIORITY);
      ((TestThread1)gAll[i]).f();
    }
    g.list();
  }
} ///:~
t t t
In main( ), several ThreadGroups are created, leafing off from each other: x has no argument but its name (a String), so it is automatically placed in the “system” thread group, while y is under x and z is under y. Note that initialization happens in textual order so this code is legal. t 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.
t t t
Two threads are created and placed in different thread groups. TestThread1 doesn’t have a run( ) method but it does have an f( ) that modifies the thread and prints something so you can see it was called. TestThread2 is a subclass of TestThread1 and its run( ) is fairly elaborate. It first gets the thread group of the current thread, then moves up the heritage tree by two levels using getParent( ). (This is contrived since I purposely place the TestThread2 object two levels down in the hierarchy.) At this point, an array of references to Threads is created using the method activeCount( ) to ask how many threads are in this thread group and all the child thread groups. The enumerate( ) method places references to all of these threads in the array gAll, then I simply move through the entire array calling the f( ) method for each thread, as well as modifying the priority. Thus, a thread in a “leaf” thread group modifies threads in parent thread groups. t 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.
t t t
The debugging method list( ) prints all the information about a thread group to standard output and is helpful when investigating thread group behavior. Here’s the output of the program: t 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:
t t t
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]
t
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]
t t t
Not only does list( ) print the class name of ThreadGroup or Thread, but it also prints the thread group name and its maximum priority. For threads, the thread name is printed, followed by the thread priority and the group that it belongs to. Note that list( ) indents the threads and thread groups to indicate that they are children of the unindented thread group. t 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é.
t t t
You can see that f( ) is called by the TestThread2 run( ) method, so it’s obvious that all threads in a group are vulnerable. However, you can access only the threads that branch off from your own system thread group tree, and perhaps this is what is meant by “safety.” You cannot access anyone else’s system thread group tree. t 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.
t t t

Controlling thread groups

t

Controller les groupes de threads

t t t
Putting aside the safety issue, one thing thread groups seem to be useful for is control: you can perform certain operations on an entire thread group with a single command. The following example demonstrates this, and the restrictions on priorities within thread groups. The commented numbers in parentheses provide a reference to compare to the output. t 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.
t t t
//: c14:ThreadGroup1.java
// How thread groups control priorities
// of the threads inside them.

public class ThreadGroup1 {
  public static void main(String[] args) {
    // Get the system thread & print its Info:
    ThreadGroup sys =
      Thread.currentThread().getThreadGroup();
    sys.list(); // (1)
    // Reduce the system thread group priority:
    sys.setMaxPriority(Thread.MAX_PRIORITY - 1);
    // Increase the main thread priority:
    Thread curr = Thread.currentThread();
    curr.setPriority(curr.getPriority() + 1);
    sys.list(); // (2)
    // Attempt to set a new group to the max:
    ThreadGroup g1 = new ThreadGroup("g1");
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    // Attempt to set a new thread to the max:
    Thread t = new Thread(g1, "A");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (3)
    // Reduce g1's max priority, then attempt
    // to increase it:
    g1.setMaxPriority(Thread.MAX_PRIORITY - 2);
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    g1.list(); // (4)
    // Attempt to set a new thread to the max:
    t = new Thread(g1, "B");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (5)
    // Lower the max priority below the default
    // thread priority:
    g1.setMaxPriority(Thread.MIN_PRIORITY + 2);
    // Look at a new thread's priority before
    // and after changing it:
    t = new Thread(g1, "C");
    g1.list(); // (6)
    t.setPriority(t.getPriority() -1);
    g1.list(); // (7)
    // Make g2 a child Threadgroup of g1 and
    // try to increase its priority:
    ThreadGroup g2 = new ThreadGroup(g1, "g2");
    g2.list(); // (8)
    g2.setMaxPriority(Thread.MAX_PRIORITY);
    g2.list(); // (9)
    // Add a bunch of new threads to g2:
    for (int i = 0; i < 5; i++)
      new Thread(g2, Integer.toString(i));
    // Show information about all threadgroups
    // and threads:
    sys.list(); // (10)
    System.out.println("Starting all threads:");
    Thread[] all = new Thread[sys.activeCount()];
    sys.enumerate(all);
    for(int i = 0; i < all.length; i++)
      if(!all[i].isAlive())
        all[i].start();
    // Suspends & Stops all threads in
    // this group and its subgroups:
    System.out.println("All threads started");
    sys.suspend(); // Deprecated in Java 2
    // Never gets here...
    System.out.println("All threads suspended");
    sys.stop(); // Deprecated in Java 2
    System.out.println("All threads stopped");
  }
} ///:~
t
//: c14:ThreadGroup1.java
// Comment les groupes de threads contrôlent les priorités
// des threads qui les composent.

public class ThreadGroup1 {
  public static void main(String[] args) {
    // Récupère le thread system & imprime ses Info:
    ThreadGroup sys =
      Thread.currentThread().getThreadGroup();
    sys.list(); // (1)
    // Réduit la priorité du groupe de thread système:
    sys.setMaxPriority(Thread.MAX_PRIORITY - 1);
    // Augmente la priorité du thread principal:
    Thread curr = Thread.currentThread();
    curr.setPriority(curr.getPriority() + 1);
    sys.list(); // (2)
    // Essaie de créer un nouveau groupe avec une priorité maximum:
    ThreadGroup g1 = new ThreadGroup("#004488">"g1");
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    // Essaie de créer un nouveau thread avec une priorité maximum:
    Thread t = new Thread(g1, "A");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (3)
    // Reduit la priorité maximum de g1, puis essaie
    // de l'augmenter:
    g1.setMaxPriority(Thread.MAX_PRIORITY - 2);
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    g1.list(); // (4)
    // Essaie de créer un nouveau thread avec une priorité maximum:
    t = new Thread(g1, "B");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (5)
    // Diminue la priorité maximum en dessous
    // de la priorité par défaut du thread:
    g1.setMaxPriority(Thread.MIN_PRIORITY + 2);
    // Regarde la priorité d'un nouveau thread
    // avant et après son changement:
    t = new Thread(g1, "C");
    g1.list(); // (6)
    t.setPriority(t.getPriority() -1);
    g1.list(); // (7)
    // Fait de g2 un groupe de thread fils de g1 et
    // essaie d'augmenter sa priorité:
    ThreadGroup g2 = new ThreadGroup(g1, "#004488">"g2");
    g2.list(); // (8)
    g2.setMaxPriority(Thread.MAX_PRIORITY);
    g2.list(); // (9)
    // Ajoute un banc de nouveaux threads à g2:
    for (int i = 0; i < 5; i++)
      new Thread(g2, Integer.toString(i));
    // Montre des informations sur tous les groupes de threads
    // et threads:
    sys.list(); // (10)
    System.out.println("Starting all threads:");
    Thread[] all = new Thread[sys.activeCount()];
    sys.enumerate(all);
    for(int i = 0; i < all.length; i++)
      if(!all[i].isAlive())
        all[i].start();
    // Suspends & Arrête tous les threads de  
    // ce groupe et de ses sous-groupes:
    System.out.println("All threads started");
    sys.suspend(); // Deprecié en Java 2
    // On n'arrive jamais ici...
    System.out.println("All threads suspended");
    sys.stop(); //  Deprecié en Java 2
    System.out.println("All threads stopped");
  }
} ///:~
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel