Synchonisation des threads
variables
partagées
Source de PerroquetsMatheux20.java
class PerroquetsMatheux20
{
private int compteur;
public static void main(String args[]) {
new PerroquetsMatheux20();
}
public PerroquetsMatheux20() {
compteur = 0;
Perroquet20 perroquetA = new Perroquet20("coco", 10);
Perroquet20 perroquetB = new Perroquet20("mille sabord", 10);
perroquetA.start();
perroquetB.start();
try {
perroquetA.join();
perroquetB.join();
}
catch(InterruptedException e) { }
System.out.println("compteur = "+compteur);
}
class Perroquet20 extends Thread
{
private String cri = null;
private int fois = 0;
public Perroquet20(String s, int i) {
cri = s;
fois = i;
}
public void repeter() {
String repete = cri + " " + compteur;
System.out.println(repete);
compteur++;
try {
Thread.sleep((int)(Math.random()*1000));
}
catch(InterruptedException e) { }
}
public void run(){
for (int n=0; n<fois; n++)
repeter();
}
}
}
|
EXECUTION
coco 0
mille sabord 1
mille sabord 2
coco 3
coco 4
mille sabord 5
mille sabord 6
coco 7
coco 8
mille sabord 9
coco 10
mille sabord 11
coco 12
mille sabord 13
coco 14
coco 15
mille sabord 16
coco 17
mille sabord 18
mille sabord 19
compteur = 20
|
|
- les lignes de la classe :
- du fait des règles de visibilité
de Java, la variable compteur est visible/accessible à
partir de la classe Perroquet20
- donc des 2 objets threads perroquetA et
perroquetB
- par contre, les variables d'instance cri
et fois de Perroquet20 existent en autant d'exemplaires que d'instances
de Perroquet20.
- les 2 threads accède donc à
un espace partagé/commun de variables.
- Contrairement au processus qui possède
son propre espace de travail clairement séparé
des autres processus, les threads sont exécutés
au sein du même processus "java".
|
le
problème de l'exclusion mutuelle
Source de PerroquetsMatheux21.java
class PerroquetsMatheux21
{
private int compteur;
public static void main(String args[]) {
new PerroquetsMatheux21();
}
public PerroquetsMatheux21() {
compteur = 0;
Perroquet21 perroquetA = new Perroquet21("coco", 10);
Perroquet21 perroquetB = new Perroquet21("mille sabord", 10);
perroquetA.setPriority(perroquetB.getPriority()%2);
perroquetA.start();
perroquetB.start();
try {
perroquetA.join();
perroquetB.join();
}
catch(InterruptedException e) { }
System.out.println("compteur = "+compteur);
}
class Perroquet21 extends Thread
{
private String cri = null;
private int fois = 0;
public Perroquet21(String s, int i) {
cri = s;
fois = i;
}
public void repeter() {
int valeur = compteur + 1;
String repete = cri + " " + valeur;
System.out.println(repete);
try {
Thread.sleep((int)(Math.random()*100));
}
catch(InterruptedException e) { }
compteur = valeur;
try {
Thread.sleep((int)(Math.random()*100));
}
catch(InterruptedException e) { }
}
public void run(){
for (int n=0; n<fois; n++)
repeter();
}
}
}
|
EXECUTION
coco 1
mille sabord 1
coco 2
mille sabord 3
coco 3
mille sabord 4
coco 5
mille sabord 6
coco 7
mille sabord 8
coco 8
mille sabord 9
coco 9
mille sabord 10
coco 10
mille sabord 11
coco 11
coco 12
mille sabord 12
mille sabord 13
compteur = 13
|
|
- les lignes de la classe :
- les 2 threads perroquet travaillent alternativement
:
- un thread peut etre suspendu au milieu
de l'exécution de sa méthode répeter pour
que le controleur de thread laisse l'autre s'exécuter.
- dans la version précédente
des Perroquet20, l'instruction compteur++ est en fait
- une lecture
- une addition
- une affectation
- donc le thread pourrait etre suspendu,
rarement mais possiblement, entre la lecture et l'écriture
de compteur
|
bloc
synchonisé
Source de PerroquetsMatheux22.java
class PerroquetsMatheux22
{
private Compteur compteur;
public static void main(String args[]) {
new PerroquetsMatheux22();
}
public PerroquetsMatheux22() {
compteur = new Compteur();
Perroquet22 perroquetA = new Perroquet22("coco", 10);
Perroquet22 perroquetB = new Perroquet22("mille sabord", 10);
perroquetA.setPriority(perroquetB.getPriority()%2);
perroquetA.start();
perroquetB.start();
try {
perroquetA.join();
perroquetB.join();
}
catch(InterruptedException e) { }
System.out.println("compteur = "+compteur.getValeur());
}
class Perroquet22 extends Thread
{
private String cri = null;
private int fois = 0;
public Perroquet22(String s, int i) {
cri = s;
fois = i;
}
public void repeter() {
synchronized(compteur) {
int valeur = compteur.getValeur() + 1;
String repete = cri + " " + valeur;
System.out.println(repete);
try {
Thread.sleep((int)(Math.random()*100));
}
catch(InterruptedException e) { }
compteur.setValeur(valeur);
}
try {
Thread.sleep((int)(Math.random()*100));
}
catch(InterruptedException e) { }
}
public void run(){
for (int n=0; n<fois; n++)
repeter();
}
}
class Compteur
{
private int valeur = 0;
public int getValeur() { return valeur; }
public void setValeur(int v) { valeur = v; }
}
}
|
EXECUTION
coco 1
mille sabord 2
coco 3
mille sabord 4
coco 5
mille sabord 6
mille sabord 7
coco 8
mille sabord 9
coco 10
mille sabord 11
coco 12
mille sabord 13
coco 14
mille sabord 15
coco 16
mille sabord 17
coco 18
mille sabord 19
coco 20
compteur = 20
|
|
- les lignes de la classe :
- le mot-clé synchronized définit
un bloc d'instruction qui ne peut s'exécuter qu'exclusivement
même si plusieurs threads souhaitent l'exécuter
:
- lorsque le thread perroquetA exécute
ce bloc synchronisé, et que le thread perroquetB souhaite
commencer l'exécution de ce même bloc, alors le
thread perroquetB doit attendre. Quand le thread perroquetA aura
finit, le thread perroquetB pourra reprendre.
- seul un thread à la fois peut exécuter
un bloc synchronisé
- on dit que le bloc en exclusion mutuelle
ou encore que c'est une section critique
- les autres threads, s'ils désirent
exécuter cette section, doivent attendre que le thread
en section critique la termine
- si plusieurs threads attendent pour un
même bloc synchronisé qui "se libère",
le controleur de thread n'en autorisera qu'un à l'éxécuter.
- L'appel à sleep() ne provoque pas
de sortie de la section critique
|

- synchronized(objet) signifie que le bloc est en exclusion mutuelle
relativement à un moniteur (monitor) de cet objet :
- sont en exclusion mutuelle, les threads
synchronisés sur le même objet
- Ci-dessous :
- le thread de gauche et celui du milieu
ont une section critique mutuelle
- le thread de droite a une section critique
mais pas avec les 2 autres threads
- le moniteur "tient" le rôle
de superviseur s'assurant que seul un thread à la fois
peut exécuter la section critique qu'il supervise : c'est
un système de verrouillage (lock)
- Le thread qui exécute synchronized
d'un objet devient propriétaire du moniteur de cet objet
- Thread.sleep ne fait pas perdre la propriété
d'un moniteur même temporairement
Il n'est pas souhaitable de mettre
un sleep(délai) dans une zone synchronisée : on
préfèrera wait(timeout)

méthode
d'instance synchonisée
Source de PerroquetsMatheux23.java
class PerroquetsMatheux23
{
private Compteur compteur;
public static void main(String args[]) {
new PerroquetsMatheux23();
}
public PerroquetsMatheux23() {
compteur = new Compteur();
Perroquet23 perroquetA = new Perroquet23("coco", 10);
Perroquet23 perroquetB = new Perroquet23("mille sabord", 10);
perroquetA.setPriority(perroquetB.getPriority()%2);
perroquetA.start();
perroquetB.start();
try {
perroquetA.join();
perroquetB.join();
}
catch(InterruptedException e) { }
System.out.println("compteur = "+compteur);
}
class Perroquet23 extends Thread
{
private String cri = null;
private int fois = 0;
public Perroquet23(String s, int i) {
cri = s;
fois = i;
}
public void repeter() {
int valeur = compteur.plus1();
String repete = cri + " " + valeur;
System.out.println(repete);
try {
Thread.sleep((int)(Math.random()*100));
}
catch(InterruptedException e) { }
}
public void run(){
for (int n=0; n<fois; n++)
repeter();
}
}
class Compteur
{
private int valeur = 0;
public synchronized int plus1() {
return ++valeur;
}
}
}
|
EXECUTION
coco 1
mille sabord 2
coco 3
coco 5
mille sabord 4
coco 6
mille sabord 7
coco 8
mille sabord 9
mille sabord 10
coco 11
coco 12
coco 13
mille sabord 14
mille sabord 15
coco 16
mille sabord 17
coco 18
mille sabord 19
mille sabord 20
compteur = 20
|
|
- les lignes de la classe :
- le mot synchronised définit le
bloc de la méthode en exclusion mutuelle
- içi c'est l'objet compteur qui
"monitorise"
- la méthode synchonisée
est aussi un mécanisme d'exclusion mutuelle sur une portion
de code :
- le moniteur qui supervise cette section
critique est celui de l'objet surquel est appelée la méthode.
- remarque :
- synchronized méthode(paramètres)
{
bloc d'instructions
}
- est équivalent à :
- méthode(paramètres)
{
synchronized(this) {
bloc d'instructions
}
}
- la synchronisation ralentit l'ensemble
de l'exécution, donc il faut limiter le nombre de portion
synchronisée et leur taille (en instructions)
- il est possible de synchroniser sur une
classe pour accéder en exclusion mutuelle sur les variables
de classe
- idem pour une méthode de classe
synchronisée
- Le mécanisme de "monitor"
d'un objet s'applique à toutes les instances de Object
:
- c'est donc un mécanisme implémenté
au coeur de JAVA
- un seul thread peut être à
la fois le propriétaire du moniteur d'un objet.
|
le problème
de coopération
des threads
Source de EcoleDesPerroquets14.java
public class EcoleDesPerroquets14 {
static String mot = null;
public static void main(String[] args) {
Perroquet14 perroquet1 = new Perroquet14("coco");
perroquet1.start();
Perroquet14 perroquet2 = new Perroquet14("jaco");
perroquet2.start();
String reponse = null;
do {
mot = reponse;
System.out.println("nouveau mot pour perroquet ? (sinon non)");
Thread.currentThread().yield();
reponse = Clavier.lireString();
}
while (! reponse.equals("non"));
System.exit(1);
}
}
class Perroquet14 extends Thread {
private String nom;
public Perroquet14(String n) {
super(n);
nom = n;
}
public void repeter() {
System.out.println(nom + " "+ EcoleDesPerroquets14.mot);
}
public void run() {
while (true) {
while (EcoleDesPerroquets14.mot == null)
try {
Thread.sleep(2000);
} catch (Exception e) { }
for (int n=0; n<3; n++)
repeter();
try {
Thread.sleep((int)(Math.random()*3000));
}
catch(InterruptedException e) { }
}
}
}
|
EXECUTION
nouveau mot pour perroquet ? (sinon non)
bla
nouveau mot pour perroquet ? (sinon non)
coco bla
coco bla
coco bla
jaco bla
jaco bla
jaco bla
blu
nouveau mot pour perroquet ? (sinon non)
coco blu
coco blu
coco blu
blo
coco blu
coco blu
coco blu
coco blu
coco blu
coco blu
nouveau mot pour perroquet ? (sinon non)
jaco blo
jaco blo
jaco blo
jaco blo
jaco blo
jaco blo
coco blo
coco blo
coco blo
.....
|
|
- les lignes de la classe :
- Une variable static "mot" est
partagée entre les 2 threads perroquets qui doivent l'apprendre
puis le répéter et le thread main qui en saisit
un nouveau.
- l'ensemble n'est pas du tout synchronisée
:
- les perroquets ne savent pas si le mot
est un nouveau à apprendre ou si c'est l'ancien.
- Au début, ils doivent attendre
avec une boucle pour le premier mot
- et si le user/professeur fournit trop
rapidement des nouveaux mots, les 2 perroquets peuvent "en
rater" !
- Le but :
- Il faudrait avoir un mécanisme
d'attente entre le professeur (user) et les élèves
perroquets :
- les élèves attendent un
nouveau mot à apprendre
- le professeur, quand il enseigne un nouveau
mot, devrait attendre que les élèves aient le temps
de l'apprendre et le répeter, avant d'en enseigner un
nouveau.
|
wait
et notifyAll
Source de EcoleDesPerroquets15.java
public class EcoleDesPerroquets15 {
public static void main(String[] args) {
AuTableau autableau = new AuTableau();
Perroquet15 perroquet1 = new Perroquet15("coco", autableau);
perroquet1.start();
Perroquet15 perroquet2 = new Perroquet15("jaco", autableau);
perroquet2.start();
String reponse = "bonjour";
do {
autableau.enseigner(reponse);
System.out.println("nouveau mot pour perroquet ? (sinon non)");
Thread.currentThread().yield();
reponse = Clavier.lireString();
}
while (! reponse.equals("non"));
System.exit(1);
}
}
class Perroquet15 extends Thread {
private String cri;
private String nom;
private AuTableau autableau;
public Perroquet15(String n, AuTableau a) {
super(n);
nom = n;
autableau = a ;
cri = "";
}
public void repeter() {
System.out.println(nom + " "+ cri);
}
public void run() {
while (true) {
cri = autableau.apprendre();
for (int n=0; n<3; n++)
repeter();
}
}
}
class AuTableau {
private String motAapprendre = null;
synchronized String apprendre() {
try {
wait();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return motAapprendre;
}
synchronized void enseigner (String mot) {
motAapprendre = mot ;
notifyAll();
}
}
|
EXECUTION
nouveau mot pour perroquet ? (sinon non)
coco bonjour
coco bonjour
coco bonjour
miam
nouveau mot pour perroquet ? (sinon non)
coco miam
coco miam
coco miam
jaco miam
jaco miam
jaco miam
encore
coco encore
coco encore
coco encore
jaco encore
jaco encore
jaco encore
nouveau mot pour perroquet ? (sinon non)
non
|
|
|
- les lignes de la classe :
- Désormais, les perroquets attendent
(wait) que le user/professeur leurs enseigne un nouveau mot et
le note au tableau.
- Dès qu'il a noté le mot
au tableau, le professeur indique (notifyAll) aux perroquets
en attente qu'ils peuvent le lire et le répéter.
- la méthode wait() d'un objet
:
- doit se trouver dans un bloc "synchronized"
sur ce même objet : elle doit acquérir le verrou
de l'objet
synchronized (objet) {
...
objet.wait();
...
}
- indique au monitor de l'objet qu'elle
se met en attente (comme sleep)
- mais (contrairement à sleep), elle
libère le verrou sur l'objet, elle termine la phase de
section critique.
- Néanmoins, quand le thead sera
réveillé/débloqué, si plusieurs thread
attendaient, un seul à la fois exécutera le reste
du bloc en section critique
- la méthode notifyAll() d'un
objet :
- doit se trouver dans un bloc "synchronized"
sur ce même objet : elle doit acquérir le verrou
de l'objet
synchronized (objet) {
...
objet.notifyAll();
...
}
- indique au monitor de l'objet que tous
les threads en attente (wait) sur l'objet doivent être
réveillés.
notify
Source de EcoleDesPerroquets16.java
public class EcoleDesPerroquets16 {
public static void main(String[] args) {
AuTableau autableau = new AuTableau();
Perroquet16 perroquet1 = new Perroquet16("coco", autableau);
perroquet1.start();
Perroquet16 perroquet2 = new Perroquet16("jaco", autableau);
perroquet2.start();
String reponse = "bonjour";
do {
autableau.enseigner(reponse);
System.out.println("nouveau mot pour perroquet ? (sinon non)");
Thread.currentThread().yield();
reponse = Clavier.lireString();
}
while (! reponse.equals("non"));
System.exit(1);
}
}
class Perroquet16 extends Thread {
private String cri;
private String nom;
private AuTableau autableau;
public Perroquet16(String n, AuTableau a) {
super(n);
nom = n;
autableau = a ;
cri = "";
}
public void repeter() {
System.out.println(nom + " "+ cri);
}
public void run() {
while (true) {
cri = autableau.apprendre();
for (int n=0; n<3; n++)
repeter();
}
}
}
class AuTableau {
private String motAapprendre = null;
synchronized String apprendre() {
try {
wait();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return motAapprendre;
}
synchronized void enseigner (String mot) {
motAapprendre = mot ;
notify();
}
}
|
EXECUTION
coco bonjour
coco bonjour
miam
coco miam
coco miam
coco miam
nouveau mot pour perroquet ? (sinon non)
encore
jaco encore
jaco encore
jaco encore
nouveau mot pour perroquet ? (sinon non)
bizarre
coco bizarre
coco bizarre
coco bizarre
nouveau mot pour perroquet ? (sinon non)
vraiment
jaco vraiment
jaco vraiment
jaco vraiment
nouveau mot pour perroquet ? (sinon non)
non
|
|
- les lignes de la classe :
- un seul perroquet élève
apprend à la fois
- un seul therad est libéré
de l'attente par notify
- notify() ne réveille qu'un thread à la fois
- il n'y a pas de spécification sur
le thread choisi ! c'est le controlleur de thread qui choisit.
|
demi-synchronisation
Source de EcoleDesPerroquets17.java
public class EcoleDesPerroquets17 {
public static void main(String[] args) {
AuTableau autableau = new AuTableau();
Perroquet17 perroquet1 = new Perroquet17("coco", autableau);
perroquet1.start();
Perroquet17 perroquet2 = new Perroquet17("jaco", autableau);
perroquet2.start();
String reponse = "bonjour";
do {
autableau.enseigner(reponse);
System.out.println("nouveau mot pour perroquet ? (sinon non)");
Thread.currentThread().yield();
reponse = Clavier.lireString();
}
while (! reponse.equals("non"));
System.exit(1);
}
}
class Perroquet17 extends Thread {
private String cri;
private String nom;
private AuTableau autableau;
public Perroquet17(String n, AuTableau a) {
super(n);
nom = n;
autableau = a ;
cri = "";
}
public void repeter() {
System.out.println(nom + " "+ cri);
}
public void run() {
while (true) {
cri = autableau.apprendre();
for (int n=0; n<3; n++) {
repeter();
try {
Thread.sleep(2000);
}
catch(InterruptedException e) { }
}
}
}
}
class AuTableau {
private String motAapprendre = null;
synchronized String apprendre() {
try {
wait();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return motAapprendre;
}
synchronized void enseigner (String mot) {
motAapprendre = mot ;
notifyAll();
}
}
|
EXECUTION
nouveau mot pour perroquet ? (sinon non)
coco bonjour
coco bonjour
coco bonjour
Miam
nouveau mot pour perroquet ? (sinon non)
jaco Miam
jaco Miam
jaco Miam
1 2 3 4
nouveau mot pour perroquet ? (sinon non)
coco 1
nouveau mot pour perroquet ? (sinon non)
nouveau mot pour perroquet ? (sinon non)
jaco 3
nouveau mot pour perroquet ? (sinon non)
coco 1
jaco 3
coco 1
jaco 3
non
|
|
- les lignes de la classe :
- les perroquets répètent
puis se mettent en attente d'un nouveau mot à apprendre
- dès qu'un nouveau mot est au tableau,
les perroquets en attente sont notifiés.
- Mais les perroquets qui ne sont pas en
attente perdront certains mots si le professeur va trop vite.
- C'est une demi-synchronisation :
- le professeur n'attend pas que les perroquets
aient eu le temps de lire et répéter.
- wait(long délai) est une attente avec un délai
d'expiration
|
Problème
du Producteur et du Consommateur
Source de EcoleDuPerroquet18.java
public class EcoleDuPerroquet18 {
public static void main(String[] args) {
AuTableau autableau = new AuTableau();
Perroquet18 perroquet = new Perroquet18("coco", autableau);
perroquet.start();
Maitre maitre = new Maitre(autableau);
maitre.start();
}
}
class Maitre extends Thread {
private AuTableau autableau;
private String reponse = null;
public Maitre (AuTableau a) {
autableau = a ;
}
public void run() {
for (int n=0; n<4; n++) {
System.out.println("nouveau mot a enseigner au perroquet ?");
Thread.currentThread().yield();
reponse = Clavier.lireString();
autableau.enseigner(reponse);
}
}
}
class Perroquet18 extends Thread {
private String cri;
private String nom;
private AuTableau autableau;
public Perroquet18(String n, AuTableau a) {
super(n);
nom = n;
autableau = a ;
cri = "";
}
public void repeter() {
System.out.println(nom + " "+ cri);
}
public void run() {
while (true) {
cri = autableau.apprendre();
for (int n=0; n<3; n++) {
repeter();
try {
Thread.sleep(2000);
}
catch(InterruptedException e) { }
}
}
}
}
class AuTableau {
private String motAuTableau = null;
synchronized String apprendre() {
String motAapprendre;
while (motAuTableau == null)
try {
wait();
} catch (Exception e) {}
motAapprendre = motAuTableau ;
motAuTableau = null;
notify();
return motAapprendre;
}
synchronized void enseigner (String motNouveau) {
while (motAuTableau != null)
try {
wait();
} catch (Exception e) {}
motAuTableau = motNouveau;
notify();
}
}
|
EXECUTION
nouveau mot a enseigner au perroquet ?
mille
coco mille
nouveau mot a enseigner au perroquet ?
coco mille
coco mille
sabords
coco sabords
nouveau mot a enseigner au perroquet ?
coco sabords
coco sabords
non
coco non
nouveau mot a enseigner au perroquet ?
coco non
coco non
|
|
- les lignes de la classe :
- le problème est simplifié
:
- un seul professeur
- un seul perroquet
- et chacun attend l'autre :
- le perroquet attend pour un nouveau mot
à apprendre
- le professeur attend que le perroquet
ait lu puis répété le mot
- Ce pattern classique est appelé
Producteur-Consommateur :
- il faut synchroniser le fonctionnement
de chacun afin que :
- le consommateur attende quand il n'y a
rien à consommer
- le producteur attende quand le consommateur
n'est pas pret à consommer.
|
Interblocage
Source de Interblocage.java
public class Interblocage {
public static void main(String[] args) {
final int[] tab1 = { 1, 2, 3, 4 };
final int[] tab2 = { 0, 1, 0, 1 };
/* tab1 et tab2 sont susceptibles d'etre modifiés
par d'autres threads */
final int[] tabAdd = new int[4];
final int[] tabSub = new int[4];
// réalise l'addition tabAdd = tab1 + tab2
Thread tacheAdd = new Thread() {
public void run() {
synchronized(tab1) {
System.out.println("Thread tacheAdd lock tab1");
travailHarassant();
synchronized(tab2) {
System.out.println("Thread tacheAdd lock tab2");
for (int i=0; i<4 ; i++)
tabAdd[i] = tab1[i] + tab2[i];
}
}
}
};
// réalise la soustraction tabAdd = tab1 - tab2
Thread tacheSub = new Thread() {
public void run() {
synchronized(tab2) {
System.out.println("Thread tacheSub lock tab2");
travailHarassant();
synchronized(tab1) {
System.out.println("Thread tacheSub lock tab1");
for (int i=0; i<4 ; i++)
tabAdd[i] = tab1[i] - tab2[i];
}
}
}
};
tacheAdd.start();
tacheSub.start();
}
static void travailHarassant() {
try {
Thread.sleep((int)(Math.random()*50+25));
}
catch (InterruptedException e) {}
}
}
|
EXECUTION
Thread tacheAdd lock tab1
Thread tacheSub lock tab2
<ctrl-C>
|
|
- les lignes de la classe :
- Supposons que tab1 et tab2 sont susceptibles
d'être modifiés par d'autres threads qui effecturaient
ces modifications en acquérant leur verrou
- Pour éviter une modification au
cours de leur calcul, les 2 threads cherchent à obtenir
les verrous de tab1 et tab2
- Le problème d'interblocage est
que :
- la tacheAdd a obtenu le lock de tab1 et
attend pour obtenir celui de tab2, puis ils les libérera
tous les 2.
- la tacheSub a obtenu le lock de tab2 et
attend pour obtenir celui de tab1, puis ils les libérera
tous les 2.
- Ils sont donc bloqués
- c'est un Deadlock
- un interblocage de taches parallèles
- qui ont acquis le verrou de certaines
ressources et cherchent à en obtenir d'autres
- le graphe des verrouillages est insastifaisable
- comme les taches ne peuvent revenir en
arrière (cad libérer des ressources), la situation
est définitivement bloquée
|
exercices
- Un professeur, 2 élèves
perroquets et un tableau.
- Le tableau du professeur est au départ
vide.
- Chaque perroquet répète
au début son cri 3 fois.
- Quand le professeur écrit au tableau
un mot au tableau, tous les perroquets devront le répéter
3 fois.
- 1 seul mot sera écrit au tableau,
puis tous termineront.
- Nos Perroquets attendent 1 à 2
secondes minimun entre chaque cri pour respirer !
- Rectifiez le code des classes ci-dessous
qui marchent mal !
public class Prog127 {
public static void main(String[] args) {
AuTableau auTableau = new AuTableau();
Perroquet20 perroquet1 = new Perroquet20("coco", " est content", auTableau);
perroquet1.start();
Perroquet20 perroquet2 = new Perroquet20("jaco", " est idiot", auTableau);
perroquet2.start();
System.out.println("mot a mettre au tableau ?");
Thread.currentThread().yield();
String reponse = Clavier.lireString();
try {
Thread.sleep(2000);
} catch(InterruptedException e) { }
}
}
|
class Perroquet20 extends Thread {
private String cri;
private String nom;
private AuTableau auTableau;
public Perroquet20(String n, String c, AuTableau a) {
super(n);
nom = n;
cri = c;
auTableau = a;
}
public void repeter() {
System.out.println(nom + " "+ cri);
}
public void run() {
for (int i=0; i<3; i++) {
repeter();
try {
Thread.sleep(1000+(int)(Math.random()*1000));
} catch(InterruptedException e) { }
}
cri = auTableau.mot;
for (int i=0; i<3; i++) {
repeter();
try {
Thread.sleep(1000+(int)(Math.random()*1000));
} catch(InterruptedException e) { }
}
}
}
|
class AuTableau {
public String mot;
public AuTableau() {
mot = null;
}
}
|
correction
- Une partie de Pingpong :
2 threads joueurs : l'un fait ping par println("ping")
sur la console et l'autre pong.
Il faut que s'affiche alternativement ping et pong !
- un producteur et des consommateurs
:
reprendre l' EcoleDuPerroquet18.java
pour plusieurs perroquets apprennent
des mots du professeur : ce dernier attendra que tous ses élèves
perroquets aients appris le nouveau mot avant de passer à
un autre
correction