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.
|