TUTORIELS 
Introduction aux "threads" avec Java
Séquences d'exécution d'un programme, les threads permettent d'optimiser le déroulement interne d'une application. Présentation de leur mise en oeuvre en Java.  (20 décembre 2001)
 

Afin de clarifier les idées rapidement, voilà de quoi schématiser simplement l'utilisation de plusieurs threads (cliquez sur les trois applets).

Dans cet exemple très visuel, l'utilisation de threads fait croire que les trois algorithmes se déroulent en même temps. Or, à moins de disposer de plusieurs processeurs et d'un système d'exploitation adéquat, votre processeur ne peut réellement gérer qu'un seul thread à la fois, mais le système d'exploitation attribue aux threads, tour à tour, un peu de la puissance de calcul du processeur.

Les threads se révèlent particulièrement utiles dans certaines applications : plus celles-ci contiennent des séquences d'instruction indépendantes (ce qui n'est pas rare), plus le multithreading apporte un avantage.
Ainsi, pour un système d'exploitation à base d'interface graphique, les threads destinés à de lourds calculs possèdent une priorité faible, c'est le contraire des threads nécessitant un peu moins de ressources, qui eux s'exécuteront plus rapidement (priorité haute), afin de rendre la main le plus rapidement possible à l'utilisateur (affichage, déplacement de fenêtres par exemple).

Un programme Java comporte toujours au moins un thread, créé lors de l'exécution.
Dans le cas des applets de l'exemple ci-dessus, c'est le navigateur qui constitue le thread principal et qui contrôle l'exécution des autres threads.

Un thread est un objet de la classe Thread. Si vous souhaitez rajouter "n" threads à votre programme, ce sont "n" objets que vous allez devoir créer.

Il existe deux méthodes pour créer un thread en Java. L'une consiste à instancier une classe dérivée de la classe Thread, l'autre repose sur l'instanciation d'une classe spéciale, appelée "Runnable".

Voyons tout de suite à quoi ressemble la première méthode à l'aide d'un exemple basique (affichage des chiffres de 1 à 10) :

(fichier threadTest.java)
public class threadTest extends Thread
{
     public void run()
     {
          for(int i = 1; i<= 10; i++)
          System.out.println(i + " " + getName());
     }

     public static void main (String[] args)
     {
          Thread t1 = new threadTest();
           t1.start();
     }
}

Découpons ce programme pas à pas.
Nous avons tout d'abord déclaré une classe threadTest qui hérite de la classe Thread, c'est obligatoire pour cette première méthode, ce qui suffit à justifier l'existence de la seconde méthode. En effet, Java ne supporte pas l'héritage multiple et dans le cas des applets, on doit systématiquement trouver quelque chose du type :

public class HelloWorld extends java.applet.Applet

On doit donc pour les applets notamment, passer obligatoirement par la seconde méthode.
La parenthèse est close, abordons la méthode "run()":

public void run()
{
     for(int i = 1; i<= 10; i++)
     System.out.println(i + " " + getName());
}


A l'intérieur de cette méthode nous pouvons définir les opérations que notre thread effectuera, en invoquant pourquoi pas d'autres méthodes.
Notre méthode "run" est ici basique, une boucle "for" de 1 à 10 suivi du nom du thread (ici par défaut).

Afin de rendre notre classe threadTest exécutable, on place une méthode "main" à l'intérieur, on crée un objet "t1", c'est un thread. Remarquez que ce n'est pas la méthode "run" qui lance le thread mais bien l'instruction...

t1.start();

... qui se chargera de déclencher l'invocation de la méthode "run".

javac threadTest.java suivi d'un java threadTest provoque l'affichage suivant :

1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
7 Thread-0
8 Thread-0
9 Thread-0
10 Thread-0

"Thread-0" est le nom par défaut donné à ce thread, ce nom passe à "Thread-1" dans le cas d'un second thread non spécifiquement nommé par l'utilisateur.

Voyons maintenant comment ajouter un thread supplémentaire à notre petit programme :

public class threadTest extends Thread
{
     // Execution en paralllele de 2 threads non synchronises
     public static void main (String[] args)
     {
          threadTest t1 = new threadTest();
          threadTest t2 = new threadTest();
          t1.start();
          t2.start();
     }

     public void run()
     {
          for(int i = 1; i<= 10; i++)
               System.out.println(i + " " + getName());
     }
}

Même principe que précedemment, nous avons crée un objet supplémentaire, "t2" qui va constituer notre nouveau thread (nommé "Thread-1") dans l'affichage provoqué par ce second exemple ci-dessous :

1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
1 Thread-1
7 Thread-0
2 Thread-1
8 Thread-0
3 Thread-1
4 Thread-1
5 Thread-1

9 Thread-0
10 Thread-0
6 Thread-1
7 Thread-1
8 Thread-1
9 Thread-1
10 Thread-1

Essayez par vous-même, les résultats obtenus sont susceptibles de changer à chaque exécution. Java n'est pas maître ici de l'ordre dans lequel les threads vont s'exécuter, c'est le système d'exploitation qui décide.

Abordons maintenant la seconde méthode disponible pour créer un thread, elle repose sur l'interface "Runnable". Celle-ci est surtout utile pour les applets et le multithreading. Voyons ce que cela donne avec notre exemple précédent (2 threads) :

(fichier threadTest2.java)
public class threadTest2 implements Runnable
{

     // Execution en parallele de 2 threads non synchronises
     public static void main (String[] args)
     {
          threadTest2 t1 = new threadTest2();
          threadTest2 t2 = new threadTest2();
          new Thread(t1).start();
          new Thread(t2).start();
     }

     public void run()
     {
          for(int i = 1; i<= 10; i++)
               System.out.println(i);
     }
}

Nous devons ici nous passer de la fonction "getname", notre classe n'hérite plus de la classe Thread dans laquelle elle était inclue. On obtient à l'affichage :

1
2
3
4
5
6
7
1
2
3
4
5
6
7

8
9
10
8
9
10

Voilà pour cette première introduction aux threads. Nous verrons par la suite comment les contrôler, nous aborderons également des notions telles que la synchronisation ou les priorités, ainsi que la communication entre threads.

 
[ Arnaud GadalJDNet
 
Accueil | Haut de page