La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Badr Benmammar Programmation concurrente et temps réel en Java.

Présentations similaires


Présentation au sujet: "Badr Benmammar Programmation concurrente et temps réel en Java."— Transcription de la présentation:

1 Badr Benmammar Programmation concurrente et temps réel en Java

2 class BavarderEtLancerLePerroquet4 { public static void main(String args[]) { Perroquet4 perroquet = new blabla(); Perroquet4("coco",5); perroquet.start(); System.out.println ("Thread bavard : " + Thread.currentThread().getName()); for (int n=0; n<15; n++) { try { Thread.sleep(1000); } catch(InterruptedException e) { } System.out.println("Thread perroquet isAlive : " + perroquet.isAlive()); } private static void blabla() { System.out.println("blabla"); } class Perroquet4 extends Thread { private String cri = null; private int fois = 0; public Perroquet4 (String s, int i) { cri = s; fois = i; } public void run() { System.out.println("Thread perroquet : " + Thread.currentThread().getName()); for (int n=0; n

3 Exécution: Thread bavard : main Thread perroquet : Thread-0 Thread perroquet isAlive : true blabla coco Thread perroquet isAlive : true blabla coco Thread perroquet isAlive : true blabla coco Thread perroquet isAlive : true blabla coco Thread perroquet isAlive : false blabla Cycle de vie dun Thread Le Thread "principal", celui qui exécute main s'appelle main. Lautre, celui du perroquet, a reçu comme nom par défaut Thread-0. La méthode isAlive() détermine si un Thread est en train d'exécuter sa méthode run. La méthode de classe currentThread() retourne un pointeur sur lobjet Thread qui appelle cette méthode. La méthode getName() donne le nom du Thread.

4 Propriétés des différents Threads class BavarderEtLancerLePerroquet5 { public static void main(String args[]) { Thread.currentThread().setName("bavard"); Perroquet5 perroquet = new Perroquet5("coco",15); perroquet.start(); for (int n=0; n<5; n++) { try { Thread.sleep(1000); } catch(InterruptedException e) { } blabla(); }} private static void blabla() { System.out.println("blabla"); }} class Perroquet5 extends Thread { private String cri = null; private int fois = 0; public Perroquet5(String s, int i) { super("perroquet"); cri = s; fois = i; } public void run(){ afficheThreads(); for (int n=0; n

5 Propriétés des différents Threads Exécution: 0-ieme Thread : bavard 1-ieme Thread : perroquet coco blabla coco blabla coco blabla coco blabla coco blabla coco 0-ieme Thread : perroquet 1-ieme Thread : DestroyJavaVM La méthode setName (String nom) permet de nommer le Thread. Le constructeur offre la possibilité de le nommer ainsi Thread (String nom). La méthode de classe activeCount () donne le nombre de Threads actifs dans le groupe de l'appelant. La méthode de classe enumerate (Thread[] tableau) stocke dans le tableau donné les références des Threads actifs dans le groupe de l'appelant et ses sous- groupes. Elle renvoie le nombre de Threads actifs obtenus. Remarquons que le Thread main, renommé bavard, a fini avant le Thread perroquet, et ne l'attend pas pour terminer.

6 Synchronisation sur terminaison class BavarderEtLancerLePerroquet6{ public static void main(String args[]) { Perroquet6 perroquet = new Perroquet6("coco",10); perroquet.start(); for (int n=0; n<5; n++) blabla(); try { perroquet.join(); } catch(InterruptedException e) { System.out.println(e.getMessage()); System.exit(2); } System.out.println("fin du Thread perroquet !"); for (int n=0; n<5; n++) blabla(); } private static void blabla() { System.out.println("blabla"); try { Thread.sleep(1000); } catch(InterruptedException e) { } }} class Perroquet6 extends Thread { private String cri = null; private int fois = 0; public Perroquet6 (String s, int i) { super ("perroquet"); cri = s; fois = i; } public void repeter() { System.out.println(cri); try {Thread.sleep(1000); } catch(InterruptedException e) { } } public void run() { for (int n=0; n

7 Synchronisation sur terminaison Exécution: blabla coco blabla coco blabla coco blabla coco blabla coco fin du Thread perroquet ! blabla La méthode join() attend la terminaison du Thread spécifié. Si le Thread est créé mais pas "starté", il est considéré comme terminé ! join() peut aussi avoir un paramètre donné qui est un timeout maximal. Les 2 Threads ne sont plus indépendants puisque le "main" attend, à une certaine étape, la terminaison (fin d'exécution) de l'autre. C'est une forme de synchronisation. Exécution en multitâche Le main attend la terminaison du Thread perroquet Le main termine son exécution perroquet.join();

8 Exemple de join() : synchroniser deux écrivains public class Ecrivain extends Thread { private String texte; public Ecrivain(String t) { texte=t; } public void run() { for (int i=0; i<10; i++) { int j=0; for (;j

9 Exemple de join() : synchroniser deux écrivains Exécution: AXBYC ABZ XC AYZ XBC AYBC AZ XBC AYBC AZ XBC ABYZ XC AYBC AZ XBC ecrivain de ABC a fini YZ XYZ ecrivain de XYZ a fini public class Prog55 { public static void main (String argv[]) { Ecrivain ecrivainA, ecrivainB; ecrivainA = new Ecrivain ("ABC"); ecrivainB = new Ecrivain ("XYZ"); ecrivainA.start(); try { ecrivainA.join(); } catch(InterruptedException e) { System.out.println(e.getMessage()); System.exit(1); } ecrivainB.start(); } } Exécution : ABC ecrivain de ABC a fini XYZ ecrivain de XYZ a fini

10 Deux Threads sans sleep class BavarderEtLancerLePerroquet7 { public static void main(String args[]) { Perroquet7 perroquet = new Perroquet7("coco",10); perroquet.start(); for (int n=0; n<10; n++) blabla(); } private static void blabla() { System.out.println("blabla"); } class Perroquet7 extends Thread { private String cri = null; private int fois = 0; public Perroquet7(String s, int i) { cri = s; fois = i; } public void repeter() { System.out.println(cri); } public void run() { for (int n=0; n

11 public class CourseInfernale1 { public static void main(String[] args) { Coureur A = new Coureur("A"); Coureur B = new Coureur("B"); A.start(); B.start(); }} class Coureur extends Thread { String nom; public Coureur(String nom) { super(nom); this.nom = nom; } public void run() { long coupsDePedale = 0; while (coupsDePedale < ) { coupsDePedale++; if ((coupsDePedale % ) == 0) { System.out.println("Coureur " + nom + " a donne " + coupsDePedale + " coups de pedale."); } } }} Répartition de temps entre deux Threads

12 Exécution: Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Java n'impose pas que le système soit "time-sliced" : cad que la même quantité de temps soit impartie aux Threads de même niveau de priorité.

13 Priorité entre Threads La méthode setPriority fixe le niveau de priorité entre les différents Threads. La valeur doit être comprise entre une valeur minimale, MIN_PRIORITY, et maximale, MAX_PRIORITY. public class CourseInfernale2 { public static void main(String[] args) { Coureur A = new Coureur("A"); Coureur B = new Coureur("B"); A.setPriority(Thread.MAX_PRIORITY); B.setPriority(Thread.MIN_PRIORITY); System.out.println("Thread Coureur " + A.nom + " a la priorite = " + A.getPriority()); System.out.println("Thread Coureur " + B.nom + " a la priorite = " + B.getPriority()); A.start(); B.start(); } class Coureur extends Thread { String nom; public Coureur(String nom) { super(nom); this.nom = nom; } public void run() { long coupsDePedale = 0; while (coupsDePedale < ) { coupsDePedale++; if ((coupsDePedale % ) == 0) { System.out.println("Coureur " + nom + " a donne " + coupsDePedale + " coups de pedale."); }

14 Priorité entre Threads Exécution: Thread Coureur A a la priorite = 10 Thread Coureur B a la priorite = 1 Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur A a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale. Coureur B a donne coups de pedale.

15 Méthode yield() La méthode yield() "rend le processeur" : elle indique au contrôleur d'exécution des Threads d'en choisir un nouveau à exécuter (donc ca pourrait être le même !). Elle est intéressante dans peu de cas. class BavarderEtLancerLePerroquet8 { public static void main(String args[]) { Perroquet8 perroquet = new Perroquet8("coco",10); perroquet.start(); for (int n=0; n<10; n++) { blabla(); Thread.currentThread().yield(); } private static void blabla() { System.out.println("blabla"); } class Perroquet8 extends Thread { private String cri = null; private int fois = 0; public Perroquet8(String s, int i) { cri = s; fois = i; } public void repeter() { System.out.println(cri); } public void run() { for (int n=0; n

16 Essayer de Stopper lexécution dun Thread class LancerEtArreterLePerroquet9 { public static void main(String args[]) { Perroquet9 perroquet = new Perroquet9("coco"); perroquet.start(); String reponse="o"; do {System.out.println("voulez-vous que le perroquet continue ? (o/n)"); Thread.currentThread().yield(); reponse = Saisie.litexte(); } while (reponse.equals("o")); }} Exécution: coco … class Perroquet9 extends Thread { private String cri = null; public Perroquet9(String s) { cri = s; } public void repeter() { System.out.println(cri); try { Thread.sleep((int)Math.random()*1000); } catch(InterruptedException e) {} } public void run() { while (true) { repeter(); yield(); } }} Larrêt de l'exécution du Thread main n'entraine pas l'arrêt du Thread perroquet. L'arrêt brutal dun Thread pouvait laisser des objets dans des états inconsistants (par exemple, des verrous pouvaient avoir été posés). C'est au programmeur de prévoir quand (et donc comment) l'exécution du Thread peut s'arrêter sans risque.

17 Stopper proprement : mot clé volatile class LancerEtArreterLePerroquet10{ public static void main(String args[]) { Perroquet10 perroquet = new Perroquet10("coco"); perroquet.start(); String reponse="o"; do { System.out.println("voulez-vous que le perroquet continue ? (o/n)"); reponse = Saisie.litexte(); } while (reponse.equals("o")); perroquet.stopper(); } class Perroquet10 extends Thread{ private volatile boolean continuer = true; private String cri = null; public Perroquet10(String s) { continuer = true; cri = s; } public void repeter() { System.out.println(cri); try { Thread.sleep((int)Math.random()*2000); } catch(InterruptedException e) { } } public void stopper() { continuer = false;} public void run() { while (continuer) { repeter(); } } }

18 Stopper proprement Exécution : coco ncoco coco La solution est très simple : une variable booléenne sert dans la méthode run pour savoir sil faut continuer ou arrêter. Cette variable doit être déclarée volatile. Pour une variable, le modificateur volatile force la JVM, avant et après chaque utilisation de la variable par un Thread, à la rafraîchir à partir de la mémoire principale au lieu d'utiliser un cache local. Cela permet de synchroniser la valeur de la variable entre plusieurs Threads.

19 Programmer une tâche en précisant un délai initial import java.util.TimerTask; import java.util.Timer; class DeclancherLePerroquet11{ public static void main(String args[]) { Perroquet11 perroquet = new Perroquet11("coco", 3); Timer timer = new Timer(); timer.schedule(perroquet, 4000); String reponse="oui"; do { System.out.println("blabla"); System.out.println("voulez-vous encore bavarder ? (o/n)"); reponse = Saisie.litexte(); } while (reponse.equals("o")); timer.cancel(); } class Perroquet11 extends TimerTask { private String cri = null; private int fois = 0; public Perroquet11(String s, int i) { cri = s; fois = i; } public void repeter() { System.out.println(cri); } public void run() { for (int i = 0; i < fois; i++) { repeter(); }

20 TimerTask public abstract class TimerTask extends Object implements Runnable TimerTask est une classe abstraite qui implémente Runnable, donc une méthode run(), il faut donc hériter de la classe TimerTask et redéfinir la méthode run() qui code la tâche à effectuer. Un Timer permet de déclencher l'exécution de tâches une ou plusieurs fois en précisant un délai initial et/ou une périodicité. Plusieurs tâches peuvent être programmées selon des programmes divers.

21 Programmer une tâche en précisant un délai initial Exécution: blabla voulez-vous encore bavarder ? (o/n) o blabla voulez-vous encore bavarder ? (o/n) coco o blabla voulez-vous encore bavarder ? (o/n) n A un Timer correspond un Thread qui exécutera successivement les tâches à effectuer. Les tâches sont des TimerTask et doivent être courte. Aucune garantie de temps réel n'est assurée par ce mécanisme. schedule(tache, long millisecondes) programme la tâche en précisant un délai initial en millisecondes. La méthode cancel() arrête la programmation du Timer.

22 Programmer une tâche avec délai initial et une périodicité import java.util.TimerTask; import java.util.Timer; class DeclancherLePerroquet11{ public static void main(String args[]) { Perroquet11 perroquet = new Perroquet11("coco", 3); Timer timer = new Timer(); timer.schedule(perroquet, 3000,2000); String reponse="oui"; do { System.out.println("blabla"); System.out.println("voulez-vous encore bavarder ? (o/n)"); reponse = Saisie.litexte(); } while (reponse.equals("o")); timer.cancel(); } class Perroquet11 extends TimerTask { private String cri = null; private int fois = 0; public Perroquet11(String s, int i) { cri = s; fois = i; } public void repeter() { System.out.println(cri); } public void run() { for (int i = 0; i < fois; i++) { repeter(); } schedule(tache, long delai, long période) programme la tâche après un délai pour une exécution périodiques : les temps sont donnés en millisecondes.

23 Programmer une tâche avec délai initial et une périodicité Exécution: blabla voulez-vous que le perroquet continue ? (o/n) coco ncoco coco

24 Partager une ressource: imprimeur public class Imprimeur1 { private String texte; public Imprimeur1() { texte=""; } public void imprimer(String t) { texte=t; for (int j=0;j

25 Exécution: AXYYZ Z AXYYZ Z AXYYZ AC XYYZ Z XABBC C AXYYZ Z AXYYZ Z XABBC C XABBC C XABBC ecrivain de XYZ a fini C ecrivain de ABC a fini Partager une ressource: imprimeur Les écrivains passent par un imprimeur pour écrire. Les 2 écrivains s'adressent maintenant à un imprimeur commun. Non seulement, les écrivains écrivent en "interleaving" (entrelacement), mais ils "écrasent" la variable texte de l'imprimeur. L'ensemble est encore illisible.

26 Ressource en exclusion mutuelle public class Imprimeur1 { private String texte; public Imprimeur1() { texte=""; } public synchronized void imprimer(String t) { texte=t; for (int j=0;j

27 Exécution : ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC XYZ ABC Xecrivain de ABC a fini YZ ecrivain de XYZ a fini Ressource en exclusion mutuelle synchronized définit un verrou/ une section en exclusion mutuelle sur la méthode imprimer : Un seul Thread au plus peut exécuter la méthode à la fois.

28 Synchronisation des threads

29 Plan Variables partagées Problème de lexclusion mutuelle Bloc synchronisé Méthode dinstance synchronisée Problème de coopération des threads wait, notifyAll et notify Demi-synchronisation (wait et sleep) Problème du Producteur et du Consommateur Interblocage

30 Variables partagées class PerroquetsMatheux20 { private int compteur; public static void main(String args[]) { new PerroquetsMatheux20(); } public PerroquetsMatheux20 () { compteur = 1; Perroquet20 perroquetA = new Perroquet20("coco", 10); Perroquet20 perroquetB = new Perroquet20("bonjour", 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

31 Exécution: coco 1 bonjour 2 bonjour 3 coco 4 bonjour 5 coco 6 bonjour 7 bonjour 8 bonjour 9 coco 10 bonjour 11 coco 12 bonjour 13 coco 14 coco 15 bonjour 16 coco 17 bonjour 18 coco 19 coco 20 compteur = 21 Variables partagées La classe Perroquet20 se situe à lintérieur de la classe PerroquetsMatheux20, et la méthode join est utilisée afin de ne pas afficher la valeur du compteur avant la terminaison des deux Threads. 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".

32 Problème de laccès concurrent (partage de ressource) 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("bonjour", 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

33 Problème de laccès concurrent (partage de ressource) Exécution: coco 1 bonjour 1 coco 2 coco 3 bonjour 3 coco 4 bonjour 4 coco 5 bonjour 5 coco 6 bonjour 7 coco 7 bonjour 8 coco 8 bonjour 9 coco 9 coco 10 bonjour 10 bonjour 11 bonjour 12 compteur = 12 Les 2 threads perroquet travaillent alternativement : un thread peut être suspendu au milieu de lexécution de sa méthode repeter pour que le contrôleur de thread laisse lautre s'exécuter.

34 Définir une section critique : Bloc synchronisé 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("bonjour", 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

35 Définir une section critique : Bloc synchronisé 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 est 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 contrôleur de thread n'en autorisera qu'un à l'exécuter. L'appel à sleep() ne provoque pas de sortie de la section critique. Exécution: bonjour 1 coco 2 bonjour 3 coco 4 bonjour 5 coco 6 coco 7 bonjour 8 coco 9 bonjour 10 bonjour 11 coco 12 coco 13 bonjour 14 coco 15 bonjour 16 bonjour 17 coco 18 coco 19 bonjour 20 compteur = 20

36 Bloc synchronisé

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

38 Méthode dinstance synchronisée 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("bonjour", 10); perroquetA.setPriority(perroquetB.getPriority()%2); perroquetA.start(); perroquetB.start(); try { perroquetA.join(); perroquetB.join(); } catch(InterruptedException e) { } System.out.println("compteur = "+compteur.valeur); } 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

39 Méthode dinstance synchronisée Exécution : coco 1 bonjour 2 bonjour 3 coco 4 coco 5 bonjour 6 bonjour 7 coco 8 bonjour 9 coco 10 bonjour 11 coco 12 bonjour 13 bonjour 14 coco 15 bonjour 16 coco 17 bonjour 18 coco 19 coco 20 compteur = 20 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 synchronisé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 sur lequel est appelée la méthode. remarque : synchronized méthode(paramètres) { 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. est équivalent à : méthode(paramètres) { synchronized(this) { bloc d'instructions } }

40 Rappel

41 Multitâche Un système dexploitation est dit multitâche ou à temps partagé lorsque plusieurs «tâches» (processus) peuvent être exécutées simultanément. 2 types de système dexploitation multitâche : Multitâche coopératif (non-préemptif) : Une forme simple de multitâche où chaque processus doit explicitement permettre à une autre tâche de sexécuter. Cette approche simplifie larchitecture du système dexploitation mais présente plusieurs inconvénients : Si un des processus ne redonne pas la main à un autre processus, par exemple si le processus est bugué, le système entier peut sarrêter. Multitâche préemptif : Pour remédier à cette situation, les systèmes ont évolué pour utiliser une approche nommée « multitâche préemptif ». Dans un tel système, le processeur signale au système dexploitation que le processus en cours dexécution doit être mis en pause pour permettre lexécution dun autre processus. Ne pas attendre des heures quun programme planté cède la priorité.

42 Processus vs Thread La plupart des systèmes dexploitation offrent la distinction entre : Processus lourd : Un programme (un ensemble dinstructions) à exécuter. Sont complètement isolés les uns des autres. Processus léger : Thread Portion de code capable de sexécuter en parallèle à dautres traitements. Ils partagent code, données et ressources. Mais peuvent disposer de leurs propres données.

43 Création de thread 2 manières pour créer un Thread : Une classe qui dérive de java.lang.Thread. java.lang.Thread implémente Runnable. Il faut redéfinir la méthode run(). Une classe qui implémente linterface Runnable Il faut implémenter la méthode run()

44 Méthode 1 : Sous-classer Thread class Thread1 extends Thread { Thread1() {...} // Le constructeur... public void run() {... // Ici ce que fait le thread }... Thread1 p1 = new Thread1(); // Création du thread p1 p1.start(); // Démarre le thread et exécute p1.run()

45 Méthode 2 : une classe qui implémente Runnable class Thread2 implements Runnable { Thread2() {...} // Constructeur... public void run() {... // Ici ce que fait le thread }... Thread2 p = new Thread2(); Thread p2 = new Thread(p);... p2.start(); // Démarre le thread et exécute p.run()

46 Quelle solution choisir ? Méthode 1 : sous-classer Thread Lorsquon désire paralléliser une classe qui nhérite pas déjà dune autre classe (classe autonome). Attention : héritage simple. Méthode 2 : implémenter Runnable Lorsquune super-classe est imposée. Cas des applets public class MyThreadApplet extends Applet implements Runnable {}

47 Applet et thread Un thread qui conte de 1 à 20, il fait laffichage à la fois dans lapplet et sur la console. import java.applet.*; import java.awt.*; public class CounterThread extends Applet implements Runnable { Thread t; int Count; public void init() { Count=0; t=new Thread(this); // t doit prendre un objet this comme paramètre t.start(); } public void run() { while (Count < 20) { Count++; repaint(); try { t.sleep(1000); } catch (InterruptedException e) {} } public void paint(Graphics g) { g.drawString(Integer.toString(Count),10,10); System.out.println("Count= "+Count); }

48 ThreadGroup ThreadGroup : dans java.lang. Plusieurs Threads peuvent sexécuter en même temps, il serait utile de pouvoir les manipuler comme une seule entité. Pour les suspendre, Pour les arrêter,... Java offre cette possibilité via lutilisation des groupes de threads : java.lang.ThreadGroup. On groupe un ensemble nommé de threads. Ils sont contrôlés comme une seule unité. La JVM crée au minimum un groupe de threads nommé main. Par défaut, un thread appartient au même groupe que celui qui la crée (son père). getThreadGroup() : pour connaitre son groupe.

49 Création dun groupe de threads Pour créer un groupe de threads : ThreadGroup groupe1 = new ThreadGroup("GP1"); Thread p1 = new Thread(groupe1, "P1"); Thread p2 = new Thread(groupe1, "P2"); Thread p3 = new Thread(groupe1, "P3"); Le contrôle des ThreadGroup passe par lutilisation des méthodes standards qui sont partagées avec Thread : Exemple : interrupt(), destroy(), Par exemple : appliquer la méthode interrupt() à un ThreadGroup revient à invoquer pour chaque Thread du groupe cette même méthode.

50 Création dune arborescence de threads ThreadGroup groupe1 = new ThreadGroup("GP1"); Thread p1 = new Thread(groupe1, "P1"); Thread p2 = new Thread(groupe1, "P2"); Thread p3 = new Thread(groupe1, "P3"); ThreadGroup groupe11 = new ThreadGroup(groupe1, "GP11"); Thread p4 = new Thread(groupe11, "P4"); Thread p5 = new Thread(groupe11, "P5");

51 Synchronisation des threads Premier type de synchronisation : Synchronisation compétitive : lorsque plusieurs threads utilisent la même ressource (exemple : imprimeur, laccès concurrents à un compte en banque). Définir un verrou / une section en exclusion mutuelle. En Java, chaque objet possède un moniteur (superviseur) qui peut garder les sections critiques. Il assure que seul un thread à la fois peut exécuter la section critique quil supervise. synchronized (objet) { instr } moniteur associé à objet. synchronized void Methode(){....} moniteur associé à la méthode. Lobjet est verrouillé pendant que le bloc synchronisé est exécuté. T1 est entrain dexécuter le bloc synchronisé T2 T3 T4 synchronized (objet) Queue dattente En Java, chaque objet possède une queue dattente

52 Moniteur associe à un objet 1 seul moniteur

53 Moniteurs associent à 2 objets 2 moniteurs Le thread qui exécute synchronized dun objet devient propriétaire du moniteur de cet objet

54 Synchronisation des threads Deuxième type de synchronisation : Synchronisation coopérative : lorsquun thread attend la fin de lexécution dun autre avant de poursuivre son exécution. Priorités entre threads : méthode setPriority(entier). Les priorités des threads se situent dans un intervalle de 1 à 10. Trois constantes représentent les valeurs limites et médianes. Plus la valeur de la priorité est élevée, plus grande sera la priorité du thread pour l'accès au processeur. MIN_PRIORITY: priorité minimum (1) NORM_PRIORITY: priorité normale (5) MAX_PRIORITY: priorité maximum (10) La priorité normale est affectée par défaut à un nouveau thread. Coureur A = new Coureur("A"); Coureur B = new Coureur("B"); A.setPriority(Thread.MAX_PRIORITY); B.setPriority(Thread.MIN_PRIORITY);

55 Synchronisation des threads Méthode join() : synchroniser deux écrivains ecrivainA = new Ecrivain ("ABC"); ecrivainB = new Ecrivain ("XYZ"); ecrivainA.start(); try { ecrivainA.join(); } catch(InterruptedException e) {} ecrivainB.start(); Autre type de coopération avec : wait, notify, notifyAll.

56 Exemple de coopération des threads (Professeur vs élèves) Un professeur qui apprends à des élèves des nouveaux mots. Les élèves doivent répéter chaque mot. Parler Maison Bonjour Discuter... Thread principal Parler Maison 2 Threads : 2 élèves

57 Problème de coopération des threads 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)"); reponse = Saisie.litexte(); } 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) { } }

58 Problème de coopération des threads Exécution: nouveau mot pour perroquet ? (sinon non) bla nouveau mot pour perroquet ? (sinon non) coco bla jaco bla blu nouveau mot pour perroquet ? (sinon non) coco blu blo coco blu nouveau mot pour perroquet ? (sinon non) jaco blo..... 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épéter, avant d'en enseigner un nouveau.

59 Coopération avec : wait et notifyAll 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)"); reponse = Saisie.litexte(); } 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) {} return motAapprendre; } synchronized void enseigner (String mot) { motAapprendre = mot ; notifyAll(); } Utiliser par les élèves Utiliser par le professeur

60 Coopération avec : wait et notifyAll Exécution: nouveau mot pour perroquet ? (sinon non) miam nouveau mot pour perroquet ? (sinon non) coco miam jaco miam encore coco encore jaco encore nouveau mot pour perroquet ? (sinon non) non

61 Coopération avec : wait et notifyAll Les trois méthodes (wait, notify et notifyAll) sont définies dans la classe java.lang.Object et sont donc héritées par toute classe. La méthode wait suspend (bloque) l'exécution d'un thread, en attendant qu'une certaine condition soit réalisée. La réalisation de cette condition est signalée par un autre thread par la méthode notify ou notifyAll. Lorsque la méthode wait est invoquée à partir d'une méthode synchronized, en même temps que l'exécution est suspendue, le verrou posé sur l'objet par lequel la méthode a été invoquée est relâché. Dès que la condition de réveil survient, le thread attend de pouvoir reprendre le verrou et continuer l'exécution. Une autre version de wait prend en argument un entier de type long qui définit la durée dattente maximale (en millisecondes). Si ce temps est dépassé, le thread est réveillé. Différence entre sleep et wait : sleep bloque lexécution mais le thread garde le verrou (termine son exécution). wait bloque lexécution mais le thread libère le verrou (un deuxième thread peut exécuter la section critique).

62 Coopération avec : wait et notifyAll

63 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 quils 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 lobjet. synchronized (objet) {... objet.wait();...} Indique au moniteur de lobjet qu'elle se met en attente (comme sleep), mais (contrairement à sleep), elle libère le verrou sur lobjet, 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. Coopération avec : wait et notifyAll

64 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 moniteur de lobjet que tous les threads en attente (wait) sur l'objet doivent être réveillés. Coopération avec : wait et notifyAll

65 notify public class EcoleDesPerroquets16 { public static void main(String[] args) { AuTableau autableau = new AuTableau(); Perroquet16 perroquet1 = new Perroquet16("coco", autableau); perroquet1.start(); Perroquet16 perroquet2 = new Perroquet15("jaco", autableau); perroquet2.start(); String reponse = "bonjour"; do {autableau.enseigner(reponse); System.out.println("nouveau mot pour perroquet ? (sinon non)"); reponse = Saisie.litexte(); } while (! reponse.equals("non")); System.exit(1); }} class Perroquet16 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) {} return motAapprendre; } synchronized void enseigner (String mot) { motAapprendre = mot ; notify(); }

66 notify Exécution: coco bonjour miam coco miam nouveau mot pour perroquet ? (sinon non) encore jaco encore nouveau mot pour perroquet ? (sinon non) bizarre coco bizarre nouveau mot pour perroquet ? (sinon non) vraiment jaco vraiment nouveau mot pour perroquet ? (sinon non) non Un seul therad est libéré de lattente par notify. Un seul perroquet élève apprend à la fois. notify() ne réveille qu'un thread à la fois, il n'y a pas de spécification sur le thread choisi ! c'est le contrôleur de thread qui choisit.

67 Demi-synchronisation (wait et sleep) public class EcoleDesPerroquets17 { 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)"); reponse = Saisie.litexte(); } while (! reponse.equals("non")); System.exit(1); }} class Perroquet17 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(); try {Thread.sleep(2000); } catch(InterruptedException e) { } } class AuTableau { private String motAapprendre = null; synchronized String apprendre() { try { wait();} catch (Exception e) {} return motAapprendre;} synchronized void enseigner (String mot) { motAapprendre = mot ; notifyAll(); } }

68 Demi-synchronisation (wait et sleep) Exécution: nouveau mot pour perroquet ? (sinon non) coco bonjour Miam nouveau mot pour perroquet ? (sinon non) jaco Miam nouveau mot pour perroquet ? (sinon non) coco 1 nouveau mot pour perroquet ? (sinon non) jaco 3 nouveau mot pour perroquet ? (sinon non) coco 1 jaco 3 coco 1 jaco 3 non Les perroquets répètent puis se mettent en attente dun nouveau mot à apprendre dès quun nouveau mot est au tableau, les perroquets en attente sont notifiés (synchronisation avec wait et notifyAll). Mais les perroquets qui ne sont pas en attente (qui ont été déjà notifiés) perdront certains mots si le professeur va trop vite (à cause du Thread.sleep(2000)). Cest une demi-synchronisation : Le professeur nattend pas que les perroquets aient eu le temps de lire et répéter.

69 Simuler une station de bus Des usagers arrivent à la station pour y attendre un bus ; un bus arrive, charge tous les usagers présents dans la station puis repart. Si un usager arrive trop tard il loupe le bus. Station de bus

70 class Station { public synchronized void attendreBus () { try { wait(); } catch (Exception e) {} } public synchronized void chargerUsagers () { notifyAll () ; } } class Usager extends Thread { private String nom ; private Station s ; private int heureArrivee ; public Usager (String nom, Station s, int heureArrivee) { this.nom = nom ; this.s = s ; this.heureArrivee = heureArrivee ; } public void run () { try { sleep (heureArrivee) ; } catch (InterruptedException e) {} System.out.println (nom + " arrive a la station") ; s.attendreBus () ; System.out.println (nom + " est monte dans le bus") ; } class Bus extends Thread { private Station s ; private int heureArrivee ; public Bus (Station s, int heureArrivee) { this.s = s ; this.heureArrivee = heureArrivee ; } public void run () { try { sleep (heureArrivee) ; } catch (InterruptedException e) {} System.out.println ("Bus arrive a la station") ; s.chargerUsagers () ; System.out.println ("Bus repart de la station") ; } Utiliser par les usagers Utiliser par le bus

71 Les 4 classes sont dans le fichier BusSimple.java class BusSimple { public static void main (String args[]) { Station Gare = new Station () ; Bus b = new Bus (Gare, 2000) ; Usager u [ ] = { new Usager ("A", Gare, 1500), new Usager ("B", Gare, 3000), new Usager ("C",Gare, 1000), new Usager ("D",Gare, 1500), new Usager ("E", Gare, 1000)} ; b.start () ; for (int i = 0 ; i < u.length ; i++) u[ i ].start () ; } Exécution : E arrive a la station C arrive a la station D arrive a la station A arrive a la station Bus arrive a la station Bus repart de la station C est monte dans le bus E est monte dans le bus D est monte dans le bus A est monte dans le bus B arrive a la station

72 Simuler un match de foot entre 2 joueurs 2 joueurs (2 threads) partage la même ressource qui est un ballon. Au départ, les deux joueurs sont bloqués par un wait car ils demandent le ballon. Le ballon est donné à lun des deux joueurs (à laide de notify). Un seul joueur peut récupérer le ballon, il possédera le ballon pendant certain moment (avec un sleep), il peut évidemment le déplacer, le lâcher par la suite et notifier le deuxième joueur qui va faire la même chose. 1er thread 2ème thread

73 Problème du Producteur et du Consommateur public class EcoleDuPerroquet18 { public static void main(String[] args) { AuTableau autableau = new AuTableau(); Perroquet18 perroquet = new Perroquet18("coco", autableau); perroquet.start(); //consommateur Maitre maitre = new Maitre(autableau); maitre.start(); //producteur }} 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 = Saisie.litexte(); 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(); }

74 Problème du Producteur et du Consommateur Le problème est simplifié, un seul professeur et 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 ny a rien à consommer. Le producteur attende quand le consommateur n'est pas prêt à consommer. Exécution: nouveau mot a enseigner au perroquet ? mille coco mille nouveau mot a enseigner au perroquet ? coco mille bb coco bb nouveau mot a enseigner au perroquet ? coco bb non coco non nouveau mot a enseigner au perroquet ? coco non

75 Semaphore en JAVA Un sémaphore encapsule un entier et deux opérations atomiques dincrémentation et de décrémentation. Avant 2005 (avant lapparition de J2SE 5.0). class Semaphore { int compteur; Semaphore (int init) { compteur=init; } public synchronized void P(){ compteur--; if (compteur<0) try{wait();} catch (InterruptedException e){} } public synchronized void V(){ compteur++; if (compteur<=0) notify(); } P() V() compteur = 4 T1 T2 T3 T4 T5 Section critique Le compteur détermine le nombre max de threads qui peuvent accéder à la section critique.

76 Semaphore en JAVA Opération P (acquire()) : décrémente le compteur s'il est positif ; bloque s'il est négatif en attendant de pouvoir le décrémenter. Opération V (release()) : incrémente le compteur. Fait un notify si le compteur est négatif ou nul. On peut voir le sémaphore comme un ensemble de jetons, avec deux opérations : Prendre un jeton, en attendant si nécessaire qu'il y en ait ; acquire(). Probablement avec wait. Déposer un jeton. release(). Probablement avec notify. Un sémaphore à 1 jeton est très similaire à un verrou. La version 1.5 de Java et son package java.util.concurrent (ainsi que ses sous- packages) fournissent des outils de synchronisation de plus haut niveau.

77 java.util.concurrent.Semaphore import java.util.concurrent.Semaphore; class Process2 extends Thread{ private int id; private Semaphore sem; public Process2(int i, Semaphore s) { id = i; sem = s; } private void busy() { try{sleep((int)(Math.random()*1000));} catch (InterruptedException e){} } private void noncritical() { System.out.println("Thread " + id + " n'est pas dans la section critique"); busy(); } private void critical() { System.out.println("Thread " + id + " entre dans la section critique"); busy(); System.out.println("Thread " + id + " sort de la section critique"); } public void run() { noncritical(); try { sem.acquire(); } catch (InterruptedException e){ } critical(); sem.release(); } public static void main(String[] args) { Semaphore sem = new Semaphore(1); Process2[] p = new Process2[4]; for (int i = 0; i < 4; i++) { p[i] = new Process2(i, sem); p[i].start(); }

78 Semaphore en JAVA Exécution : Semaphore sem = new Semaphore(1); Thread 0 n'est pas dans la section critique Thread 3 n'est pas dans la section critique Thread 2 n'est pas dans la section critique Thread 1 n'est pas dans la section critique Thread 3 entre dans la section critique Thread 3 sort de la section critique Thread 2 entre dans la section critique Thread 2 sort de la section critique Thread 1 entre dans la section critique Thread 1 sort de la section critique Thread 0 entre dans la section critique Thread 0 sort de la section critique

79 Semaphore en JAVA Exécution : Semaphore sem = new Semaphore(4); Thread 0 n'est pas dans la section critique Thread 1 n'est pas dans la section critique Thread 3 n'est pas dans la section critique Thread 2 n'est pas dans la section critique Thread 0 entre dans la section critique Thread 2 entre dans la section critique Thread 3 entre dans la section critique Thread 1 entre dans la section critique Thread 2 sort de la section critique Thread 3 sort de la section critique Thread 0 sort de la section critique Thread 1 sort de la section critique

80 Application des sémaphores Gestion des entrées/sorties dun parking Un parking de capacité N places. Gestion dune salle dattente. Chez un médecin, coiffeur, assurance, … M chaises disponibles.

81 Interblocage public class Interblocage { public static void main(String[] args) { final int[] tab1 = { 1, 2, 3, 4 }; final int[] tab2 = { 0, 1, 0, 1 }; final int[] tabAdd = new int[4]; final int[] tabSub = new int[4]; 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]; } }; 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) {} }

82 Interblocage Supposons que tab1 et tab2 sont susceptibles d'être modifiés par d'autres threads qui effectueraient 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 tâches parallèles qui ont acquis le verrou de certaines ressources et cherchent à en obtenir d'autres, le graphe des verrouillages est insastifaisable, comme les tâches ne peuvent revenir en arrière (cad libérer des ressources), la situation est définitivement bloquée. Exécution : Thread tacheAdd lock tab1 Thread tacheSub lock tab2


Télécharger ppt "Badr Benmammar Programmation concurrente et temps réel en Java."

Présentations similaires


Annonces Google