12. Exclusion mutuelle
Introduction
Le mécanisme d'exclusion mutuelle présent dans Java est le moniteur.
Si l'on désire définir une section critique, afin de s'assurer de
la cohérence des données, nous devons utiliser le mot-clé
synchronized
. C'est de cette manière que l'on crée un
moniteur.
Sécurisation d'une méthode
Lorsque l'on crée une instance d'une certaine classe, on crée également
un moniteur qui lui est associé. Lorsque l'on applique le
modificateur synchronized
,
on place la méthode (le bloc de code) dans ce moniteur, ce qui
assure l'exclusion mutuelle.
Exemple
class mutexAcc {
int accumulateur = 0;
public synchronized void stocke(int val) {
accumulateur += val;
}
public int lit() {
return accumulateur;
}
}
L'opération d'incrémentation +=
prend
plusieurs instructions, et un changement de contexte entre elles
pourrait créer une incohérence des résultats. Le modificateur
synchronized
indique que la méthode stocke
fait partie du moniteur de l'instance, empêchant son exécution
simultanée par plusieurs processus. Si le moniteur est déja occupé, les
processus suivants seront mis en attente. L'ordre de réveil des
processus n'est pas déterministe.
Sécurisation de blocs de code
L'utilisation de méthodes synchronisées trop longues peut créer une baisse
d'efficacité. Avec Java, il est possible de placer n'importe quel
bloc dans un moniteur,
ce qui permet ainsi de réduire la longueur des sections critiques.
Dans l'exemple suivant, le code de methode1
et de methode2
est équivalent.
synchronized void methode1() {
// section critique...
}
void methode2() {
synchronized(this) {
// section critique...
}
}
Exemple
public class Tortue {
private Point pos;
private int angle;
public Tortue(int x,int y,int angle) {
// ...
}
public synchronized void tourne(int degres) {
angle += degres;
}
public synchronized void avance(int distance) {
pos.x += (int) ((double)distance*Math.cos((double)angle));
pos.y += (int) ((double)distance*Math.sin((double)angle));
}
public int angle() {
return angle;
}
public synchronized Point pos() {
return new Point(pos.x,pos.y);
}
}
public class mutexLogo {
public int lectureEntier() {
// ...
// lecture d'un nombre entier
// pouvant prendre du temps
// ...
}
public static void carre(Tortue tortue) {
int largeur = lectureEntier();
int longueur = lectureEntier();
synchronized (tortue) {
tortue.tourne(90);tortue.avance(largeur);
tortue.tourne(90);tortue.avance(longueur);
tortue.tourne(90);tortue.avance(largeur);
tortue.tourne(90);tortue.avance(longueur);
}
// autres taches...
}
}
Comme nous l'avons vu, quand le modificateur
synchronized
qualifie une méthode, on place cette méthode
dans le moniteur de l'instance. Cela permet de sécuriser l'accès
à une instance particulière d'un objet. En créant un bloc
synchronized (tortue)
, on entre dans le moniteur associé à
l'instance tortue
. Dans l'exemple ci-dessus, si un processus
est en train d'afficher un carré en faisant appel à
mutexLogo.carre(tortue)
, un autre processus ne pourra pas déplacer
la tortue. Malgré tout, pendant que l'on se trouve dans le méthode
carre
et que l'on est en train de lire les dimensions du carré,
un autre processus pourra utiliser la tortue. En effet, le moniteur n'est pas
occupé, parce que la méthode n'est pas synchronized
, seul un
bloc l'est.
Sécurisation des variable de classes
Considérons maintenant le cas oł il faut sécuriser l'accès à une
variable de classe. La solution est simple, il faut créer un
moniteur qui est commun à toutes les instances de la classe. La
méthode getClass()
retourne la classe de l'instance
dans laquelle on l'appelle. Nous pouvons maintenant créer un
moniteur qui utilise le résultat de getClass()
comme
"verrou".
class mutexStatic {
private int accumulateur = 0;
private static int acces = 0;
public synchronized void stocke(int val) {
accumulateur += val;
synchronized (getClass()) {
acces += 1;
}
}
public int lit() {
synchronized (getClass()) {
acces += 1;
}
return accumulateur;
}
public int acces() {
return acces;
}
}
Cet exemple définit une classe d'accumulateur qui incrémente
acces
chaque fois que l'on accède à stocke
ou à lit
. La variable acces
est une variable
de classe (déclarée public
),
elle est donc partagée par les différentes instances de cette classe.
La méthode getClass()
retourne un objet de type
Class
avec lequel on crée un nouveau moniteur.
Index général - Index concepts - Règles BNF
© 1996, DIP Genève, Alexandre Maret & Jacques Guyot
page générée Fri Jun 21 15:41:32 MET DST 1996