Java - programmation concurrente

1 796 vues

Publié le

Chapitre 2 de la formation "Java avancé", qui est composée de :
1 - introspection et annotations
2 - programmation concurrente
3 - communications distantes
4 - administration et supervision avec JMX
5 - utilisation du code natif avec JNI

Publié dans : Technologie
0 commentaire
2 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
1 796
Sur SlideShare
0
Issues des intégrations
0
Intégrations
1
Actions
Partages
0
Téléchargements
79
Commentaires
0
J’aime
2
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Java - programmation concurrente

  1. 1. Programmation concurrente
  2. 2. antislashn.org Java avancé - Programmation concurrente 2 - 2 / 94Les threads● Java possède le concept de thread● la JVM sappuie sur les threads de lOS sous-jacent– ou les simules si OS monotâche● Permet de créer des applications dont certainesparties sexécutent en parallèle● La JVM possède des threads● le thread principal => méthode main● des threads secondaires pour la gestion de la JVM
  3. 3. antislashn.org Java avancé - Programmation concurrente 2 - 3 / 94Multitâche et threads● Un thread est un flux de contrôle à lintérieur duneapplicationSystème dexploitationApplication CApplication BMachine virtuelle JavaApplication AThread 1Thread 2Thread 3Variables localesVariables localesVariables localesmémoire delapplication
  4. 4. antislashn.org Java avancé - Programmation concurrente 2 - 4 / 94Les threads● Chaque thread exécute son code indépendamment des autresthreads● les threads peuvent coopérer entre eux● Les threads donnent lillusion dune exécution simultanée deplusieurs tâches● Accès aux données par un thread● les variables locales des méthodes dun thread sont différentes pour chaquethread● si deux threads exécutent la même méthode, chacun obtient un espace mémoireséparé pour les variables locales de la méthode● les objets et variables dinstances peuvent être partagés entre les threadsdun même programme Java.● les variables statiques sont automatiquement partagées
  5. 5. antislashn.org Java avancé - Programmation concurrente 2 - 5 / 94Les threads● Un thread possède● un nom● un identifiant● une priorité– Thread.MIN_PRIORITY => 1– Thread.NORM_PRIORITY => 5– Thread.MAX_PRIORITY => 10● le status deamon ou non● un groupe● un code à exécuter– méthode run()● un état
  6. 6. antislashn.org Java avancé - Programmation concurrente 2 - 6 / 94Les threads● La JVM arrête son exécution lorsque :● la méthode System.exit() est invoquéeou● tous les threads sont morts– si le thread nest pas un daemon● les daemons nempêchent pas la JVM de sarrêter
  7. 7. antislashn.org Java avancé - Programmation concurrente 2 - 7 / 94Thread – cycle de vie
  8. 8. antislashn.org Java avancé - Programmation concurrente 2 - 8 / 94Les thread● Création dun thread● par spécialisation de la classe Thread– redéfinition de la méthode run()– lancement par la méthode start() sur linstance● par implémentation de linterface Runnable– codage de la méthode run()– passer linstance de la classe à une instance de Thread– méthode start() sur linstance de Thread
  9. 9. antislashn.org Java avancé - Programmation concurrente 2 - 9 / 94Spécialisation de la classe Threadpublic class Task extends Thread {private int delai;public Task(int delai, String nom) {this.delai = delai;setName(nom);this.setName(nom);}@Overridepublic void run() {System.out.format(">>> DEBUT TACHE %s de %d s.n", getName(), delai);try {this.sleep(delai * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.format(">>> FIN TACHE %s de %d s.n", getName(), delai);}}
  10. 10. antislashn.org Java avancé - Programmation concurrente 2 - 10 / 94Implémentation de Runnableclass MyRunnable implements Runnable{@Overridepublic void run() {try {System.out.println("DEBUT THREAD");Thread.sleep(1_000);System.out.println("FIN THREAD");} catch (InterruptedException e) {e.printStackTrace();}}}public class MainRunnable {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new MyRunnable());t.start();}}
  11. 11. antislashn.org Java avancé - Programmation concurrente 2 - 11 / 94Arrêt dun thread● Une partie des méthodes de la classe Thread sontdépréciées● stop(), resume(), suspend(), destroy()● Le thread sarrête à la fin de sa méthode run()● La méthode interrupt() positionne un flag demandantlinterruption● si le thread nest pas en attente● utiliser alors les méthodes– interrupted() : renvoie le flag et le remet à false– isInterrupted() : renvoie le flag sans le remettre à false
  12. 12. antislashn.org Java avancé - Programmation concurrente 2 - 12 / 94Arrêt dun thread● Si létat du thread est RUNNABLE● interrupted() évalue le flag dinterruption et onpeut stopper la méthode run()● Si létat du thread est en attente● suite à sleep(), join() ou wait()– il reçoit une InterruptionException● suite à une attente sur une E/S– il reçoit un ClosedByInterruptionException● on peut alors stopper le thread dans le traitement delexception
  13. 13. antislashn.org Java avancé - Programmation concurrente 2 - 13 / 94Arrêt dun threadpublic class ThreadInterrupt implements Runnable {private int id;public ThreadInterrupt(int id){this.id = id;}@Overridepublic void run() {int i = 0;while(!Thread.interrupted()){System.out.printf("thread id : %d - valeur de la boucle %dn",id,i++ );//Traitement longfor(long k=1 ; k<1000000 ; k++)for(long r=1; r<1000 ;r++);}System.out.printf(">>> FIN EXECUTION thread %d - status :%bn",id,Thread.currentThread().isInterrupted());}}état RUNNABLE
  14. 14. antislashn.org Java avancé - Programmation concurrente 2 - 14 / 94Arrêt dun threadpublic class ThreadInterrupt implements Runnable {private int id;public ThreadInterrupt(int id){this.id = id;}@Overridepublic void run() {int i = 0;while(!Thread.interrupted()){System.out.printf("thread id : %d - valeur de la boucle %dn",id,i++ );try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.printf(">>> CATCH thread %d - status :%bn",id,Thread.currentThread().isInterrupted());Thread.currentThread().interrupt();}}System.out.printf(">>> FIN EXECUTION thread %d - status :%bn",id,Thread.currentThread().isInterrupted());}}état TIMED_WAITING
  15. 15. antislashn.org Java avancé - Programmation concurrente 2 - 15 / 94Arrêt dun threadpublic class ThreadInterruptMain {public static void main(String[] args) {Thread t1 = new Thread(new ThreadInterrupt(1));Thread t2 = new Thread(new ThreadInterrupt(2));t1.start();t2.start();Scanner in = new Scanner(System.in);System.out.println("Entrez le numéro du thread à arrêter : ");int num = in.nextInt();switch(num){case 1:System.out.printf("Etat du thread t1 : %sn",t1.getState());t1.interrupt();break;case 2:System.out.printf("Etat du thread t2 : %sn",t2.getState());t2.interrupt();break;}}}
  16. 16. antislashn.org Java avancé - Programmation concurrente 2 - 16 / 94Arrêt dun thread● Attente de larrêt● méthode join()– attend la terminaison dun thread– appel bloquant tant que le thread est en vie● retourne immédiatement si le thread nest pas en vie– pas démarré, arrêté● Redémarrage dun thread● un thread mort ne peut pas être redémarré● une instance de Thread ne peut-être utilisée quuneseule fois– une exception IllegalThreadStateException est levée
  17. 17. antislashn.org Java avancé - Programmation concurrente 2 - 17 / 94Concurrence● Dans un environnement monothread● si il y a écriture dune valeur dans une variable● la lecture de la variable renverra la valeur écrite– si celle-ci na pas été modifiée entre temps● Dans un environnement multithread● les lectures et écritures peuvent avoir être exécutéesdans des threads différents il ny a pas de garantiequun thread lise la valeur écrite par un autre thread
  18. 18. antislashn.org Java avancé - Programmation concurrente 2 - 18 / 94Concurence● Deux threads incrémentent un variable● au départ la variable vaut 1● la valeur attendue après les deux incrémentation est 3Thread 1● récupère A dans un registre● incrémente le registreThread 2● récupère A dans un registre● incrémente le registre● transfert du registre en mémoireA == 1● transfert du registre en mémoireA == 2
  19. 19. antislashn.org Java avancé - Programmation concurrente 2 - 19 / 94Concurrence● Laccès et laffectation est garantie en Java surtous les types sauf long et double● Il ny a pas de garanti quun thread ne prenne pasle contrôle entre 2 opérations atomiques● Pour que le code soit atomique, il faut que lobjetsoit utilisé comme moniteur● technique pour synchroniser plusieurs tâches quiutilisent des ressources partagées
  20. 20. antislashn.org Java avancé - Programmation concurrente 2 - 20 / 94Concurrenceclass Foo{private int a;private int b = 2;public Foo(int val){a=val;b=2*a;}public void changer(){a++;b=2*a;System.out.printf("%s - a == %d, b ==%dn",Thread.currentThread().getName(),a,b);}}class ThreadFoo extends Thread{private Foo foo;public ThreadFoo(Foo foo){this.foo = foo;}public void run(){for(int i=0 ; i<10 ; i++)foo.changer();}}code non atomique
  21. 21. antislashn.org Java avancé - Programmation concurrente 2 - 21 / 94Concurrencepublic class SynchronisationMain {public static void main(String[] args) {Foo foo = new Foo(10);ThreadFoo t0 = new ThreadFoo(foo);ThreadFoo t1 = new ThreadFoo(foo);t0.start();t1.start();}}Thread-1 - a == 12, b == 24Thread-0 - a == 12, b == 24Thread-1 - a == 13, b == 26Thread-1 - a == 15, b == 30
  22. 22. antislashn.org Java avancé - Programmation concurrente 2 - 22 / 94Concurrence● Verrou dexclusion mutuelle● verrou mutex● un seul thread peut acquérir un mutex● si deux threads essaient d’acquérir un verrou, un seuly parvient– lautre thread doit attendre que le premier thread restitue leverrou pour continuer
  23. 23. antislashn.org Java avancé - Programmation concurrente 2 - 23 / 94Concurrence● Le mot clé synchronized permet déviter queplusieurs threads utilisent le même code en mêmetemps● Tout objet peut jour le rôle de moniteur● chaque objet possède un verrou– si un thread prend le verrou aucun autre ne peut utiliser lecode synchronized marqué par ce verrou● différentes approches dutilisation de synchronized
  24. 24. antislashn.org Java avancé - Programmation concurrente 2 - 24 / 94Concurrence● Réentrance● si un thread demande un verrou déjà verrouillé par auautre thread, le thread demandeur est bloqué● si un thread tente de prendre un verrou quil détientdéjà la requête réussit● les verrous sont acquis par le thread et non par unappel– au verrou est associé un thread propriétaire et un compteurdacquisition– lorsque le compteur passe à zéro le verrou est libéré
  25. 25. antislashn.org Java avancé - Programmation concurrente 2 - 25 / 94Concurrence● Synchronisation implicite sur this● synchronized est placé en tant que modificateur deméthode– efficace car toute la méthode est verrouillée– peut poser un problème de performance si les traitementssont longs...public synchronized void changer(){a++;b=2*a;System.out.printf("%s - a == %d, b == %dn",Thread.currentThread().getName(),a,b);}...Thread-0 - a == 11, b == 22Thread-0 - a == 12, b == 24Thread-1 - a == 13, b == 26Thread-1 - a == 14, b == 28Thread-1 - a == 15, b == 30
  26. 26. antislashn.org Java avancé - Programmation concurrente 2 - 26 / 94Concurrence● Synchronisation sur bloc de code● on ne synchronise quune partie du code en leprotégeant par synchronized...public void changer(){synchronized (this) {a++;b=2*a;}System.out.printf("%s - a == %d, b == %dn",Thread.currentThread().getName(),a,b);}...
  27. 27. antislashn.org Java avancé - Programmation concurrente 2 - 27 / 94Concurrence● Synchronisation sur un objet● le moniteur est alors lobjet...private Object monitor = new Object();...public void changer(){synchronized (monitor) {System.out.printf("DEBUT %s - a == %d, b == %dn",Thread.currentThread().getName(),a,b);a++;b=2*a;System.out.printf("FIN %s - a == %d, b == %dn",Thread.currentThread().getName(),a,b);}}...le moniteur est une instance dObject
  28. 28. antislashn.org Java avancé - Programmation concurrente 2 - 28 / 94Concurrence● Synchronisation de la classe● permet de protéger les variables statiques duneclasseclass Foo1 {private static int a = 0;static void setA(int a) {Foo1.a = a;}static int getA() {return a;}}class Foo2 {void methodFoo2(int a) throws ClassNotFoundException {synchronized (Class.forName("org.antislashn.formation.Foo1")) {Foo1.setA(a);System.out.printf("%s - valeur de a : %dn", Thread.currentThread().getName(), Foo1.getA());}}}
  29. 29. antislashn.org Java avancé - Programmation concurrente 2 - 29 / 94Synchronisation entre threads● Pour éviter linterblocage de threads on utilise lesméthodes wait(), notify(), notifyAll()● si wait() est invoqué à lintérieur dune méthodesynchronisée– le thread actuel est bloqué et mis en liste dattente– le moniteur est déverrouillé– le thread suspendu sera réveillé par une notification sur lemoniteur● notify() pour libérer un thread de la liste● notifyAll() pour libérer tous les threads de la liste
  30. 30. antislashn.org Java avancé - Programmation concurrente 2 - 30 / 94Concurrence● Thread : méthodes dattente et de notification● wait()– attend larrivée dune condition● le thread en cours est mis en attente● le verrou est libéré, dautres thread peuvent alors exécuter desméthodes synchronisées avec le même verrou– doit être invoquée dans un bloc synchronized● notify()– notifie un thread en attente dune condition– doit être invoquée dans un bloc synchronized
  31. 31. antislashn.org Java avancé - Programmation concurrente 2 - 31 / 94Concurrence● Thread : méthodes dattente et de notification● notifyAll()– notifie tous les threads en attente dune condition– doit être invoquée dans un bloc synchronized● wait(int delay)– attend larrivée dune condition avec un timeout● le verrou est libéré● sleep(int delay)– provoque une attente● le verrou nest pas libéré● cf. aussi TimeUnit.MILLISECONDS.sleep(int ms)
  32. 32. antislashn.org Java avancé - Programmation concurrente 2 - 32 / 94Concurrence● Double verroupublic class DoubleLock {private final Object lock1 = new Object();private final Object lock2 = new Object();public void foo() throws InterruptedException{synchronized (lock1) {synchronized (lock2) {while(...){lock2.wait();}}}}public void notifier(){lock2.notify();}}foo() verrouille lock1 tant que lock2.wait()nest pas terminé
  33. 33. antislashn.org Java avancé - Programmation concurrente 2 - 33 / 94Concurrence● Reportez-vous à latelier 1
  34. 34. antislashn.org Java avancé - Programmation concurrente 2 - 34 / 94Concurrence et collections● Parcours de collection par itérateur ou boucle typefor-each● les itérateurs renvoyés les collections synchroniséesne sont pas conçus pour gérer les modificationsconcurrentes– exception ConcurrentModificationException– solution : verrouiller la collection pendant le parcours● certains itérateurs sont cachés– exemple : appel toString() sur une collection● itération cachée pour appel de toString() sur chaque élément
  35. 35. antislashn.org Java avancé - Programmation concurrente 2 - 35 / 94Java 5 – principaux ajouts● Amélioration des collections synchronisées● ConcurrentHashMap● CopyOnWriteArrayList● Queue● BlockingQueue
  36. 36. antislashn.org Java avancé - Programmation concurrente 2 - 36 / 94Java 5 – principaux ajouts● API de concurrence● historiquement développée par Doug LEA● JSR 166● Ensemble de classes et interfaces● package java.util.concurrent● Atomicité● package java.util.concurrent.atomic●AtomicBoolea, AtomicLong, ...
  37. 37. antislashn.org Java avancé - Programmation concurrente 2 - 37 / 94Java 5 – principaux ajouts● Les loquets● CountDownLatch– permet à un ou plusieurs threads dattendre quun ensembledévénements se produise● FutureTask– utilisé par le framework Executor– représente des tâches asynchrones dont on veut exploiter lerésultat● Semaphore– contrôle le nombre dactivités pouvant simultanémentaccéder à une ressource ou à lexécution dune action– gère un nombre de jetons virtuels
  38. 38. antislashn.org Java avancé - Programmation concurrente 2 - 38 / 94Java 5 – principaux ajouts● Les barrières● permettent de bloquer un groupe de thread jusquà cequun événement survienne– les loquets ne sont pas réutilisables, les barrières le sont● CyclicBarrier– permet à un certains nombre de threads de ce donnerrendez-vous● les threads invoquent await() lorsquils atteignent la barrière, labarrière souvre lorsque tous les threads sont arrivés● Exchanger– permet à deux threads déchanger des données
  39. 39. antislashn.org Java avancé - Programmation concurrente 2 - 39 / 94Lock● interface Lock● remplace le bloc synchronized● peut être utilisé avec des conditions● lock() : acquisition du verrou● unlock() : libération du verrou– idiome : unlock est invoqué dans un bloc finallylock.lock();try{// corps du traitement}finally{lock.unlock();}
  40. 40. antislashn.org Java avancé - Programmation concurrente 2 - 40 / 94Lock● ReentrantLock● verrou dexclusion mutuel standard– le verrou nest détenu que par un seul thread● ReentrantReadWriteLock● expose deux objets Lock– readLock() renvoie un verrou en lecture– writeLock() renvoie un verrou en écriture● permet davoir plusieurs consommateurs en lecturepour un producteur en écriture– optimisations sur les données accédées souvent en lecture
  41. 41. antislashn.org Java avancé - Programmation concurrente 2 - 41 / 94Condition● Une condition est créée par linstance de Lock● méthode newCondition()● Lutilisation des conditions remplace lutilisationdes méthodes de gestion dun moniteur Object● wait(), notify(), notifyAll()● await() : met le thread propriétaire du lock enattente● signal() : réveille le thread en attente suite à unawait()
  42. 42. antislashn.org Java avancé - Programmation concurrente 2 - 42 / 94Lock et Condition● Dans lexemple suivant● si take() est invoqué sur un buffer vide, le thread estmis en attente jusquà ce que des items soientdisponibles● de même si put() est invoqué sur un buffer plein, lethread est mis en attente jusquà ce quil y ait de laplace pour au moins un item
  43. 43. antislashn.org Java avancé - Programmation concurrente 2 - 43 / 94Lock et Conditionclass BoundedBuffer {final Lock lock = new ReentrantLock();final Condition full = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length)full.await();items[putptr] = x;if (++putptr == items.length)putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}...}libère le verrou
  44. 44. antislashn.org Java avancé - Programmation concurrente 2 - 44 / 94Lock et Conditionclass BoundedBuffer {...public Object take() throws InterruptedException {lock.lock();try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length)takeptr = 0;--count;full.signal();return x;} finally {lock.unlock();}}libère le verrou
  45. 45. antislashn.org Java avancé - Programmation concurrente 2 - 45 / 94Concurrence● Reportez-vous à latelier 2
  46. 46. antislashn.org Java avancé - Programmation concurrente 2 - 46 / 94Volatile● Chaque thread possède un cache local● Le mot clé volatile permet de sassurer quunevariable utilisée par plusieurs thread sera toujoursà jour● la JVM rafraîchira le contenu de la variable à chaquefois quelle est utilisée– la variable ne sera pas mise dans le cache local des Threads● attention : voir la prise en compte de volatil parlimplémentation de la JVM
  47. 47. antislashn.org Java avancé - Programmation concurrente 2 - 47 / 94ThreadLocal● Permet à des threads exécutant le même coderun() de posséder leur propre variable● ThreadLocal<T> est utilisé comme attribut du thread– les valeurs sont accessible par get() et set()● méthodes– T get() retourne la valeur associé au thread, si pas devariable pour le thread initialValue() est invoquée– void set(T) met à jour la variable associée au thread– T initialValue() est invoqué au premier get() siaucun set() na été appelé– void remove() retire la valeur associée au thread
  48. 48. antislashn.org Java avancé - Programmation concurrente 2 - 48 / 94Communication entre threads● Certains flux Java permettent la communicationentre threads● un thread sera producteur doctets ou de char– classes PipedOutputStream et PipedWriter● un thread sera consommateur doctets ou char– classes PipedInputStream et PipedReader
  49. 49. antislashn.org Java avancé - Programmation concurrente 2 - 49 / 94Communication entre threads● Reportez-vous à latelier 3
  50. 50. antislashn.org Java avancé - Programmation concurrente 2 - 50 / 94Tâches● Planification de tâches par la classe Timer● toutes les tâches tournent dans un même thread– schedule() et scheduleAtFixedRate() pour planifierune tâche– cancel() pour supprimer les tâches non démarrées– purge() pour retirer les tâches● les tâches sont codées dans une classe dérivant deTimerTask– run() pour le code de la tâche
  51. 51. antislashn.org Java avancé - Programmation concurrente 2 - 51 / 94CountDownLatch● Permet de retarder lexécution des threads tantquune opération nest pas terminée● une fois loquet dans son état terminal ouvert, il ne peutplus changer détat● exemple :– garanti quun calcul ne sera pas lancé tant que toutes lesressources nécessaires nauront pas étés initialisées– garanti quun service ne sera pas lancé tant que tous lesservices dépendant ne sont pas activés
  52. 52. antislashn.org Java avancé - Programmation concurrente 2 - 52 / 94CountDownLatch● La méthode await() permet de bloquer lesthreads jusquà ce que le loquet soit ouvert● CountDownLatch(int count) : crée le loquet avecun certains nombre de tours● void await() : mise en attente tant que le compteurnest pas nul● void countDown() : décrémente le compteur● long getCount() : renvoie le compteur
  53. 53. antislashn.org Java avancé - Programmation concurrente 2 - 53 / 94CountDownLatch● Exemple dattente de fin de plusieurs threadsclass StopThread extends Thread {private final CountDownLatch latch;private long delay;public StopThread(CountDownLatch latch, long ms) {this.latch = latch;this.delay = ms;}public void run() {try {System.out.printf(">>> START %sn", Thread.currentThread().getName());Tread.sleep(delay);} catch (InterruptedException e) {e.printStackTrace();} finally {latch.countDown();System.out.printf(">>> END %s countDown==%dn",Thread.currentThread().getName(), latch.getCount());}}}
  54. 54. antislashn.org Java avancé - Programmation concurrente 2 - 54 / 94CountDownLatch● Exemple dattente de fin de plusieurs threads(suite)public class CountDownLatchTest {public static void main(String[] args) throws InterruptedException {int nbTaches = 5;CountDownLatch latch = new CountDownLatch(nbTaches);for(int i=0 ; i< nbTaches ; i++){StopThread t = new StopThread(latch, 1000);t.start();}latch.await();System.out.println("FIN DE TOUTES LES TACHES");}}
  55. 55. antislashn.org Java avancé - Programmation concurrente 2 - 55 / 94CountDownLatch● Reportez vous à latelier 4
  56. 56. antislashn.org Java avancé - Programmation concurrente 2 - 56 / 94CyclicBarrier● Permet de définir un point dattente à plusieursthreads● la barrière est débloquées lorsque tous les processusenregistrés ont atteint ce point● par rapport au loquet– le loquet est éphémère, une fois ouvert il ne peu plus êtreutilisé– un loquet attend des événements, tandis que une barrièreattends dautres threads
  57. 57. antislashn.org Java avancé - Programmation concurrente 2 - 57 / 94CyclicBarrier● CyclicBarrier(int parts) : création dunebarrière avec un certain nombre de participants● CyclicBarrier(int parts,Runnable barrierAction)création dune barrière avec un certain nombre departicipants et lancement dune action lorsque labarrière est ouverte● int await() : permet au thread de senregistrerauprès de la barrière, lappel est bloquant tant queles autres threads participants nont pas fini
  58. 58. antislashn.org Java avancé - Programmation concurrente 2 - 58 / 94CyclicBarrier● Exemple dattente avant lancement dun autrethread● chaque tâche additionne une ligne dune matrice● lorsque toutes les tâches sont finies une addition dechaque ligne est effectuéeprivate static int matrix[][] = { { 1 },{ 2, 2 },{ 3, 3, 3 },{ 4, 4, 4, 4 },{ 5, 5, 5, 5, 5 } };
  59. 59. antislashn.org Java avancé - Programmation concurrente 2 - 59 / 94CyclicBarrier● Exemple dattente avant lancement dun autrethreadpublic static void main(String args[]) {final int rows = matrix.length;results = new int[rows];Runnable merger = new Runnable() {public void run() {int sum = 0;for (int i = 0; i < rows; i++) {sum += results[i];}System.out.println("Results are: " + sum);}};CyclicBarrier barrier = new CyclicBarrier(rows, merger);for (int i = 0; i < rows; i++) {new Summer(barrier, i).start();}System.out.println("Waiting...");}thread a lancer lorsquetoutes les tâches serontterminéescréation de la barrière avecnombre de tâches et threadà lancer lorsque la barrièresera ouverte
  60. 60. antislashn.org Java avancé - Programmation concurrente 2 - 60 / 94CyclicBarrier● Exemple dattente avant lancement dun autre thread(suite) private static class Summer extends Thread {int row;CyclicBarrier barrier;Summer(CyclicBarrier barrier, int row) {this.barrier = barrier;this.row = row;}public void run() {int columns = matrix[row].length;int sum = 0;for (int i = 0; i < columns; i++) {sum += matrix[row][i];}results[row] = sum;System.out.println("Results for row " + row + " are : " + sum);try {barrier.await();} catch (InterruptedException ex) {ex.printStackTrace();} catch (BrokenBarrierException ex) {ex.printStackTrace();}}}attente des autres participants
  61. 61. antislashn.org Java avancé - Programmation concurrente 2 - 61 / 94CyclicBarrier● Reportez-vous à latelier 5
  62. 62. antislashn.org Java avancé - Programmation concurrente 2 - 62 / 94Exchanger● Exchanger<V> : forme de barrière formée dedeux parties séchangeant des données● exemple : un thread remplit un buffer de données,tandis doit lire un buffer– les thread échangent alors un buffer plein contre un buffervide● léchange est provoqué dès que les deux threadsappel la méthode V exchange(V x)
  63. 63. antislashn.org Java avancé - Programmation concurrente 2 - 63 / 94Exchanger● Exemple déchange de Stringpublic class ExchangerTest {public static void main(String[] args) {Exchanger<String> exchanger = new Exchanger<String>();ExchangerRunnable exchangerRunnable1 = new ExchangerRunnable(exchanger, "A");ExchangerRunnable exchangerRunnable2 = new ExchangerRunnable(exchanger, "B");new Thread(exchangerRunnable1).start();new Thread(exchangerRunnable2).start();}}création de léchangeur de Stringon passe léchangeur aux 2 threads
  64. 64. antislashn.org Java avancé - Programmation concurrente 2 - 64 / 94Exchanger● Exemple déchange de Stringclass ExchangerRunnable implements Runnable{Exchanger exchanger = null;Object object = null;public ExchangerRunnable(Exchanger exchanger, Object object) {this.exchanger = exchanger;this.object = object;}public void run() {try {Object previous = this.object;this.object = this.exchanger.exchange(this.object);System.out.println(Thread.currentThread().getName() +" exchanged " + previous + " for " + this.object);} catch (InterruptedException e) {e.printStackTrace();}}}appel de léchange, bloquant jusquà ceque les 2 threads soient près
  65. 65. antislashn.org Java avancé - Programmation concurrente 2 - 65 / 94Exchanger● Reportez-vous à latelier 6
  66. 66. antislashn.org Java avancé - Programmation concurrente 2 - 66 / 94Semaphore● Encapsule un entier● contrainte de positivité● opérations dincrémentation et de décrémentationatomiques● Gère un ensemble de jetons virtuels● le nombre initial de jeton est passé au constructeur deSemaphore● acquire() : lactivité prend un jeton, appel bloquant● release() : lactivité rend le jeton
  67. 67. antislashn.org Java avancé - Programmation concurrente 2 - 67 / 94Semaphore● Constructeurs● Semaphore(int permits, boolean fair) créerle sémaphore en précisant le nombre de jetons et ladistribution des jetons dans lordre des demandes● Semaphore(int permits) créer le sémaphore enprécisant le nombre de jetons, sans garantie dedistribution dans lordre des demandes– équivalent à Semaphore(int permits,false)
  68. 68. antislashn.org Java avancé - Programmation concurrente 2 - 68 / 94Semaphore● Permet dimplémenter des pools de ressourcesclass BoundedList<T>{private final List<T> liste;private final Semaphore semaphore;public BoundedList(int bound){this.liste = Collections.synchronizedList(new ArrayList<T>());this.semaphore = new Semaphore(bound);}public boolean add(T item) throws InterruptedException{semaphore.acquire();boolean ok = false;try{ok = liste.add(item);return ok;}finally{if(!ok)semaphore.release();}}...}tentative d’acquisition dun jetonmise en attente si pas de jeton disponible
  69. 69. antislashn.org Java avancé - Programmation concurrente 2 - 69 / 94Semaphore● Permet dimplémenter des pools de ressourcesclass BoundedList<T>{private final List<T> liste;private final Semaphore semaphore;public BoundedList(int bound){this.liste = Collections.synchronizedList(new ArrayList<T>());this.semaphore = new Semaphore(bound);}public boolean add(T item) throws InterruptedException{semaphore.acquire();boolean ok = false;try{ok = liste.add(item);return ok;}finally{if(!ok)semaphore.release();}}...}tentative d’acquisition dun jetonmise en attente si pas de jeton disponible
  70. 70. antislashn.org Java avancé - Programmation concurrente 2 - 70 / 94Exécution de tâches● JDK 1.5 met à disposition des exécuteurs detâches● interface Executor : découple les appels de tâchede leur exécution, en précisant lutilisation des threads,leur ordonnancement, …● interface ExecutorService : gestion des tâchesasynchrones– permet lutilisation de méthodes de terminaison deprocessus, cf. interface Future● interface ScheduleExecutorService : gestion detâches périodiques
  71. 71. antislashn.org Java avancé - Programmation concurrente 2 - 71 / 94Exécution de tâches● Les exemples suivants utilisent la classeRunnableTaskpublic class RunnableTask implements Runnable {private int nbSecondes;public RunnableTask(int nbSecondes) {this.nbSecondes = nbSecondes;}@Overridepublic void run() {System.out.println(">>> START "+Thread.currentThread().getName()+" pour "+nbSecondes+" s");try {Thread.sleep(nbSecondes*1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(">>> FIN "+Thread.currentThread().getName());}}
  72. 72. antislashn.org Java avancé - Programmation concurrente 2 - 72 / 94Exécution de tâches● Exemple sur un seul threadpublic class MonoThreadRunnableTaskExecutor {private List<Runnable> runnables = new ArrayList<>();private ExecutorService service = Executors.newSingleThreadExecutor();public void add(Runnable runnable){runnables.add(runnable);}public void start(){for(Runnable r : runnables){service.execute(r);}service.shutdown();}public static void main(String[] args) {MonoThreadRunnableTaskExecutor executor = new MonoThreadRunnableTaskExecutor();executor.add(new RunnableTask(1));executor.add(new RunnableTask(2));executor.add(new RunnableTask(4));executor.add(new RunnableTask(3));executor.start();System.out.println("Fin des exécutions");}}
  73. 73. antislashn.org Java avancé - Programmation concurrente 2 - 73 / 94Exécution de tâches● Résultat de lexécution des tâches sur un seulthread>>> START pool-1-thread-1 pour 1 s>>> FIN pool-1-thread-1>>> START pool-1-thread-1 pour 2 s>>> FIN pool-1-thread-1>>> START pool-1-thread-1 pour 4 s>>> FIN pool-1-thread-1>>> START pool-1-thread-1 pour 3 s>>> FIN pool-1-thread-1
  74. 74. antislashn.org Java avancé - Programmation concurrente 2 - 74 / 94Exécution de tâches● Exemple sur un plusieurs threadpublic class MultiThreadRunnableTaskExecutor {private List<Runnable> runnables = new ArrayList<>();private ExecutorService service = Executors.newFixedThreadPool(10);public void add(Runnable runnable){runnables.add(runnable);}public void start(){for(Runnable r : runnables){service.execute(r);}service.shutdown();}public static void main(String[] args) {MultiThreadRunnableTaskExecutor executor = new MultiThreadRunnableTaskExecutor();executor.add(new RunnableTask(1));executor.add(new RunnableTask(2));executor.add(new RunnableTask(4));executor.add(new RunnableTask(3));executor.start();System.out.println("Fin des exécutions");}}
  75. 75. antislashn.org Java avancé - Programmation concurrente 2 - 75 / 94Exécution de tâches● Résultat de lexécution des tâches sur un seulthread>>> START pool-1-thread-2 pour 2 s>>> START pool-1-thread-3 pour 4 s>>> START pool-1-thread-1 pour 1 sFin des exécutions>>> START pool-1-thread-4 pour 3 s>>> FIN pool-1-thread-1>>> FIN pool-1-thread-2>>> FIN pool-1-thread-4>>> FIN pool-1-thread-3
  76. 76. antislashn.org Java avancé - Programmation concurrente 2 - 76 / 94Tâches asynchrones● Future● interface représentant le traitement résultat duntraitement asynchrone● instances créées par ExecutorService● Callable● permet le retour dune valeur après lexécution dunetâche– ce que ne permet pas la méthode run() de Runnable● le callable est soumis à un exécuteur, le frameworkretourne un Future
  77. 77. antislashn.org Java avancé - Programmation concurrente 2 - 77 / 94Tâches asynchrones● Exemple de Callablepublic class Compteur implements Callable<Long> {private final long nb;public Compteur(long nb){this.nb = nb;}@Overridepublic Long call() throws Exception {System.out.println(">>> "+Thread.currentThread().getName());long sum = 0;for(long i=0; i<nb; i++)sum+=i;return sum;}}
  78. 78. antislashn.org Java avancé - Programmation concurrente 2 - 78 / 94Tâches asynchrones● Exemple dutilisation de Futurepublic class CompteurFutureTest {private static final int NB_THREADS = 50;public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(NB_THREADS);List<Future<Long>> futures = new ArrayList<Future<Long>>();for(int i=100 ; i< 120 ; i++){Callable<Long> callable = new Compteur(i);Future<Long> future = executor.submit(callable);futures.add(future);}executor.shutdown();long total = 0;for(Future<Long> f : futures){try {total = f.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}System.out.println("TOTAL = "+total);}}
  79. 79. antislashn.org Java avancé - Programmation concurrente 2 - 79 / 94Tâches asynchrones● Reportez-vous à latelier 7
  80. 80. antislashn.org Java avancé - Programmation concurrente 2 - 80 / 94Java 6 - ajouts● Deux types de collections sont ajoutées● Deque : file à double entrée– garanti les insertions et suppression efficaces aux deuxextrémités– implémenté par ArrayDeque et LinkedBlockingDeque● adaptées au pattern "Vol de tâche"– le consommateur – producteur utilise une seule file detâches partagées par tous les consommateurs– le vol de tâche utilise un file double par consommateur, unconsommateur ayant épuisé sa file peut voler la tâche à lafin dune file double dun autre
  81. 81. antislashn.org Java avancé - Programmation concurrente 2 - 81 / 94Java 7 : ajouts● TransferQueue● interface modélisant une file dattente bloquante– le producteur attend que le consommateur prenne ce quil a misdans la file● ThreadLocalRandom● générateur de nombres aléatoires local à un thread– évite de partager une instance de Random entre plusieurs threads● Phaser● barrière de synchronisation réutilisable et supportant unnombre de tâches enregistrées pouvant varier durantlexécution
  82. 82. antislashn.org Java avancé - Programmation concurrente 2 - 82 / 94Java 7 : fork/join● Problème de base : traiter de grandes quantités dedonnées paquet par paquet● chaque paquet peut être traiter de manière indépendantedes autres● chaque paquet peut fournir un résultat partiel● les résultats partiels sont ensuite fusionnés● La décomposition en sous tâches peut être● statique : découpage dun tableau en sous-tableau● dynamique : découverte dune arborescence dun systèmede fichier– quel volume de tâches à créer ?
  83. 83. antislashn.org Java avancé - Programmation concurrente 2 - 83 / 94Java 7 : fork/join● Différentes approches sont envisageables● traiter les paquets les uns après les autres● traiter les paquets en parallèle avec un point desynchronisation type CyclicBarrier● utiliser le traitement parallèle avec ForkJoinTask
  84. 84. antislashn.org Java avancé - Programmation concurrente 2 - 84 / 94Java 7 : fork/join● Deux classes de base● ForkJoinTask– modélise une tâche unique qui sera envoyée à une réservede threads– peut générer dautres tâches du même type qui serontenvoyées à la même réserve de threads● ForkJoinPool– gère la réserve de threads– la réserve reçoit les tâches et le dispatche aux threads– réserve conçue pour quun grand nombre de tâchesélémentaires soit traitées par un nombre restreint de threads
  85. 85. antislashn.org Java avancé - Programmation concurrente 2 - 85 / 94Java 7 : fork/join● La machine qui exécute la tâche doit posséderplusieurs processeurs● La tâche est récursive● RecursiveTask : avec renvoi de résultat● RecursiveAction : sans renvoi de résultat● Algorithme de base dutilisation du frameworkfork/join :if (my portion of the work is small enough)do the work directlyelsesplit my work into two piecesinvoke the two pieces and wait for the results
  86. 86. antislashn.org Java avancé - Programmation concurrente 2 - 86 / 94Java 7 : fork/join● La javadoc précise quune tâche élémentaire● ne doit pas comporter de synchronisation afin déviterles blocages● ne doivent pas partager de variables● doivent pouvoir être exécutées rapidement
  87. 87. antislashn.org Java avancé - Programmation concurrente 2 - 87 / 94Java 7 : fork/join● La javadoc précise quune tâche élémentaire● ne doit pas comporter de synchronisation afin déviterles blocages● ne doivent pas partager de variables● doivent pouvoir être exécutées rapidement
  88. 88. antislashn.org Java avancé - Programmation concurrente 2 - 88 / 94Java 7 : fork/joinForkJoinPoolForkJoinPoolTâche longuesoccupe du découpageen sous tâchesTâche longuesoccupe du découpageen sous tâcheslance la tâchesous-tâche sous-tâche sous-tâchesous-tâchesous-tâchesous-tâche sous-tâchesous-tâchefork()join()
  89. 89. antislashn.org Java avancé - Programmation concurrente 2 - 89 / 94Java 7 : fork/join● ForkJoinTask<V>● V : type résultat● deux méthodes principales– join() : retourne le résultat de la tâche (V)● bloquante tant que que la tâche nest pas finie– fork() : lance une autre tâche dans la même réserve depool que la tâche courante● une même tâche ne doit pas appeler plus dune fois sa méthodefork()● spécialisée par RecusiveAction et RecursiveTask<V>– compute() : méthode exécutée par la tâche
  90. 90. antislashn.org Java avancé - Programmation concurrente 2 - 90 / 94Java 7 : fork/join● Reportez-vous à latelier 8
  91. 91. antislashn.org Java avancé - Programmation concurrente 2 - 91 / 94Objets immuables● La classe doit être déclarée final● pour éviter la modification dune instance par héritage● Tous les champs doivent être déclarés final● La référence this ne doit jamais être exportée● pas de return this ;
  92. 92. antislashn.org Java avancé - Programmation concurrente 2 - 92 / 94Objets immuables● Les propriétés référençant des objets nonimmuables doivent :● être privées● ne jamais être exportées● représenter lunique référence à lobjet– faire des copies défensives
  93. 93. antislashn.org Java avancé - Programmation concurrente 2 - 93 / 94Objets immuablesprivate final Date theDate;public MaClasse(Date theDate) {this.theDate = theDate;}@Overridepublic String toString() {return theDate.toString();}Date d = new Date();MaClasse c = new MaClasse(d);d.setYear(98);System.out.println(c);cette propriété peut-être exportéeprivate final Date theDate;public MaClasse(Date theDate) {this.theDate = (Date) theDate.clone();}copie défensive
  94. 94. antislashn.org Java avancé - Programmation concurrente 2 - 94 / 94Ressources● Livres● Java Threads– auteurs : Scott Oaks, Henry Wong– éditeur : OReilly● Programmation concurrente en Java– auteur : Brian Goetz– éditeur : PEARSON● web● http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html● http://www.oracle.com/technetwork/articles/java/fork-join-422606.html● http://gee.cs.oswego.edu/dl/papers/fj.pdf● http://blog.paumard.org/

×