Le mécanisme d'exclusion mutuelle présent dans l'environnement
Java est le moniteur, que l'on implémente grâce au
modificateur synchronized
.
Le principe de base est qu'un seul processus ne peut entrer dans un
moniteur si celui-ci est occupé.
Mais voyons tout d'abord comment créer plusieurs processus. Nous
pouvons tout simplement étendre la classe java.lang.Thread
et remplacer sa méthode run()
par notre propre
algorithme. Lorsque l'on appelle la méthode start()
,
la méthode run()
est déclenchée, et elle s'arrête lors
d'un appel à stop()
.
class afficheur extends Thread {
/** constructeur permettant de nommer le processus */
public afficheur(String s) {
super(s);
}
/** affiche son nom puis passe le controle au suivant */
public void run() {
while (true) {
System.out.println("je suis le processus "+getName());
Thread.yield(); // passe le controle
}
}
}
class thread12 {
public static void main(String args[]) {
afficheur thread1 = new afficheur("1");
afficheur thread2 = new afficheur("2");
thread1.start();
thread2.start();
while (true) {
System.out.println("je suis la tache principale !");
Thread.yield();
}
}
}
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
Le problème est que la méthode Thread.stop()
est
qualifiée de final
. On
ne peut donc pas la remplacer.
Une autre solution est possible.
L'interface Runnable
permet de créer un objet, que l'on utilisera ensuite comme
constructeur d'un
Thread
. C'est la méthode start()
de l'objet
qui sera responsable de la création et de l'activation du thread.
class afficheurRunnable implements Runnable {
boolean cont = true;
String nomProcessus;
Thread th;
/** constructeur permettant de nommer le processus */
public afficheurRunnable(String s) {
nomProcessus = s;
}
public void start() {
if (th == null) {
th = new Thread(this,nomProcessus);
th.start();
}
}
public void stop() {
if (th != null) {
th.stop();
th = null;
}
}
/** affiche son nom puis passe le controle au suivant */
public void run() {
while (cont) {
System.out.println("je suis le processus "+th.getName());
Thread.yield(); // passe le controle
}
}
}
class runnable12 {
public static void main(String args[]) {
afficheurRunnable run1 = new afficheurRunnable("1");
afficheurRunnable run2 = new afficheurRunnable("2");
run1.start();
run2.start();
while (true) {
System.out.println("je suis la tache principale !");
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}
}
}
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
Comme nous l'avons vu dans les exemples précédents, on utilise
Thread.yield()
afin de redonner le contrôle à
l'ordonnanceur. De cette manière, quel que soit le comportement de
la machine virtuelle Java, les différents processus s'entrelaceront.
Il est également important de s'assurer que les accès concurrents aux variables et méthodes ne mettent pas en péril la validité des données. Pour ce faire, veuillez vous reporter à la page décrivant les mécanismes d'exclusion mutuelle de Java.
Pour les mécanismes de synchronisation inter-processus, veuillez vous référer à la page décrivant les signaux.