java - programmation concurrente

94
Programmation concurrente

Upload: franck-simon

Post on 26-Jun-2015

1.221 views

Category:

Technology


2 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Java - programmation concurrente

Programmation concurrente

Page 2: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 2 / 94

Les threads

● Java possède le concept de thread● la JVM s'appuie sur les threads de l'OS sous-jacent

– ou les simules si OS monotâche

● Permet de créer des applications dont certaines parties s'exé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

Page 3: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 3 / 94

Multitâche et threads

● Un thread est un flux de contrôle à l'intérieur d'une application

Système d'exploitation

Application C

Application B

Machine virtuelle Java

Application A

Thread 1

Thread 2

Thread 3

Variables locales

Variables locales

Variables locales

mémoire del'application

Page 4: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 4 / 94

Les threads

● Chaque thread exécute son code indépendamment des autres threads

● les threads peuvent coopérer entre eux

● Les threads donnent l'illusion d'une exécution simultanée de plusieurs tâches

● Accès aux données par un thread● les variables locales des méthodes d'un thread sont différentes pour chaque

thread

● si deux threads exécutent la même méthode, chacun obtient un espace mémoire séparé pour les variables locales de la méthode

● les objets et variables d'instances peuvent être partagés entre les threads d'un même programme Java.

● les variables statiques sont automatiquement partagées

Page 5: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 5 / 94

Les 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

Page 6: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 6 / 94

Les threads

● La JVM arrête son exécution lorsque :● la méthode System.exit() est invoquée

ou● tous les threads sont morts

– si le thread n'est pas un daemon● les daemons n'empêchent pas la JVM de s'arrêter

Page 7: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 7 / 94

Thread – cycle de vie

Page 8: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 8 / 94

Les thread

● Création d'un thread● par spécialisation de la classe Thread

– redéfinition de la méthode run()

– lancement par la méthode start() sur l'instance

● par implémentation de l'interface Runnable– codage de la méthode run()

– passer l'instance de la classe à une instance de Thread

– méthode start() sur l'instance de Thread

Page 9: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 9 / 94

Spécialisation de la classe Thread

public 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);

}

}

Page 10: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 10 / 94

Implémentation de Runnable

class 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();

}}

Page 11: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 11 / 94

Arrêt d'un thread

● Une partie des méthodes de la classe Thread sont dépréciées● stop(), resume(), suspend(), destroy()

● Le thread s'arrête à la fin de sa méthode run()

● La méthode interrupt() positionne un flag demandant l'interruption● si le thread n'est pas en attente● utiliser alors les méthodes

– interrupted() : renvoie le flag et le remet à false

– isInterrupted() : renvoie le flag sans le remettre à false

Page 12: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 12 / 94

Arrêt d'un thread

● Si l'état du thread est RUNNABLE● interrupted() évalue le flag d'interruption et on

peut 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 de l'exception

Page 13: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 13 / 94

Arrêt d'un thread

public 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 %d\n",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 :

%b\n",id,Thread.currentThread().isInterrupted());}

}

état RUNNABLE

Page 14: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 14 / 94

Arrêt d'un thread

public 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 %d\n",id,i++ );try {

Thread.sleep(1000);} catch (InterruptedException e) {

System.out.printf(">>> CATCH thread %d - status :%b\n",id,Thread.currentThread().isInterrupted());

Thread.currentThread().interrupt();}

}System.out.printf(">>> FIN EXECUTION thread %d - status :

%b\n",id,Thread.currentThread().isInterrupted());}

}

état TIMED_WAITING

Page 15: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 15 / 94

Arrêt d'un thread

public 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 : %s\n",t1.getState());t1.interrupt();break;

case 2:System.out.printf("Etat du thread t2 : %s\n",t2.getState());t2.interrupt();break;

}}

}

Page 16: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 16 / 94

Arrêt d'un thread

● Attente de l'arrêt● méthode join()

– attend la terminaison d'un thread– appel bloquant tant que le thread est en vie

● retourne immédiatement si le thread n'est pas en vie– pas démarré, arrêté

● Redémarrage d'un thread● un thread mort ne peut pas être redémarré● une instance de Thread ne peut-être utilisée qu'une

seule fois– une exception IllegalThreadStateException est levée

Page 17: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 17 / 94

Concurrence

● Dans un environnement monothread ● si il y a écriture d'une valeur dans une variable● la lecture de la variable renverra la valeur écrite

– si celle-ci n'a pas été modifiée entre temps

● Dans un environnement multithread● les lectures et écritures peuvent avoir être exécutées

dans des threads différents il n'y a pas de garantie qu'un thread lise la valeur écrite par un autre thread

Page 18: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 18 / 94

Concurence

● Deux threads incrémentent un variable● au départ la variable vaut 1● la valeur attendue après les deux incrémentation est 3

Thread 1

● récupère A dans un registre● incrémente le registre

Thread 2

● récupère A dans un registre● incrémente le registre● transfert du registre en mémoire

A == 1

● transfert du registre en mémoire

A == 2

Page 19: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 19 / 94

Concurrence

● L'accès et l'affectation est garantie en Java sur tous les types sauf long et double

● Il n'y a pas de garanti qu'un thread ne prenne pas le contrôle entre 2 opérations atomiques

● Pour que le code soit atomique, il faut que l'objet soit utilisé comme moniteur● technique pour synchroniser plusieurs tâches qui

utilisent des ressources partagées

Page 20: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 20 / 94

Concurrence

class 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 ==%d\n",

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

Page 21: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 21 / 94

Concurrence

public 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

Page 22: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 22 / 94

Concurrence

● Verrou d'exclusion mutuelle● verrou mutex● un seul thread peut acquérir un mutex● si deux threads essaient d’acquérir un verrou, un seul

y parvient– l'autre thread doit attendre que le premier thread restitue le

verrou pour continuer

Page 23: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 23 / 94

Concurrence

● Le mot clé synchronized permet d'éviter que plusieurs threads utilisent le même code en même temps

● 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 le code synchronized marqué par ce verrou

● différentes approches d'utilisation de synchronized

Page 24: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 24 / 94

Concurrence

● Réentrance● si un thread demande un verrou déjà verrouillé par au

autre thread, le thread demandeur est bloqué● si un thread tente de prendre un verrou qu'il détient

déjà la requête réussit● les verrous sont acquis par le thread et non par un

appel– au verrou est associé un thread propriétaire et un compteur

d'acquisition– lorsque le compteur passe à zéro le verrou est libéré

Page 25: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 25 / 94

Concurrence

● Synchronisation implicite sur this● synchronized est placé en tant que modificateur de

méthode– efficace car toute la méthode est verrouillée– peut poser un problème de performance si les traitements

sont longs

...public synchronized void changer(){

a++;b=2*a;System.out.printf("%s - a == %d, b == %d\n",

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

Page 26: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 26 / 94

Concurrence

● Synchronisation sur bloc de code● on ne synchronise qu'une partie du code en le

protégeant par synchronized

...public void changer(){

synchronized (this) {a++;b=2*a;

}System.out.printf("%s - a == %d, b == %d\n"

,Thread.currentThread().getName(),a,b);}...

Page 27: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 27 / 94

Concurrence

● Synchronisation sur un objet● le moniteur est alors l'objet

...private Object monitor = new Object();...public void changer(){

synchronized (monitor) {System.out.printf("DEBUT %s - a == %d, b == %d\n",

Thread.currentThread().getName(),a,b);a++;b=2*a;System.out.printf("FIN %s - a == %d, b == %d\n",

Thread.currentThread().getName(),a,b);}

}...

le moniteur est une instance d'Object

Page 28: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 28 / 94

Concurrence

● Synchronisation de la classe● permet de protéger les variables statiques d'une

classeclass 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 : %d\n", Thread.currentThread().getName(), Foo1.getA());

}}

}

Page 29: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 29 / 94

Synchronisation entre threads

● Pour éviter l'interblocage de threads on utilise les méthodes wait(), notify(), notifyAll()● si wait() est invoqué à l'intérieur d'une méthode

synchronisée– le thread actuel est bloqué et mis en liste d'attente– le moniteur est déverrouillé– le thread suspendu sera réveillé par une notification sur le

moniteur● notify() pour libérer un thread de la liste● notifyAll() pour libérer tous les threads de la liste

Page 30: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 30 / 94

Concurrence

● Thread : méthodes d'attente et de notification● wait()

– attend l'arrivée d'une condition● le thread en cours est mis en attente● le verrou est libéré, d'autres thread peuvent alors exécuter des

méthodes synchronisées avec le même verrou

– doit être invoquée dans un bloc synchronized● notify()

– notifie un thread en attente d'une condition– doit être invoquée dans un bloc synchronized

Page 31: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 31 / 94

Concurrence

● Thread : méthodes d'attente et de notification● notifyAll()

– notifie tous les threads en attente d'une condition– doit être invoquée dans un bloc synchronized

● wait(int delay)

– attend l'arrivée d'une condition avec un timeout● le verrou est libéré

● sleep(int delay)

– provoque une attente● le verrou n'est pas libéré● cf. aussi TimeUnit.MILLISECONDS.sleep(int ms)

Page 32: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 32 / 94

Concurrence

● Double verrou

public 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()n'est pas terminé

Page 33: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 33 / 94

Concurrence

● Reportez-vous à l'atelier 1

Page 34: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 34 / 94

Concurrence et collections

● Parcours de collection par itérateur ou boucle type for-each● les itérateurs renvoyés les collections synchronisées

ne sont pas conçus pour gérer les modifications concurrentes– 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

Page 35: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 35 / 94

Java 5 – principaux ajouts

● Amélioration des collections synchronisées● ConcurrentHashMap● CopyOnWriteArrayList● Queue● BlockingQueue

Page 36: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 36 / 94

Java 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, ...

Page 37: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 37 / 94

Java 5 – principaux ajouts

● Les loquets● CountDownLatch

– permet à un ou plusieurs threads d'attendre qu'un ensemble d'événements se produise

● FutureTask– utilisé par le framework Executor– représente des tâches asynchrones dont on veut exploiter le

résultat● Semaphore

– contrôle le nombre d'activités pouvant simultanément accéder à une ressource ou à l'exécution d'une action

– gère un nombre de jetons virtuels

Page 38: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 38 / 94

Java 5 – principaux ajouts

● Les barrières● permettent de bloquer un groupe de thread jusqu'à ce

qu'un événement survienne– les loquets ne sont pas réutilisables, les barrières le sont

● CyclicBarrier– permet à un certains nombre de threads de ce donner

rendez-vous● les threads invoquent await() lorsqu'ils atteignent la barrière, la

barrière s'ouvre lorsque tous les threads sont arrivés

● Exchanger– permet à deux threads d'échanger des données

Page 39: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 39 / 94

Lock

● 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 finally

lock.lock();try{

// corps du traitement}finally{

lock.unlock();}

Page 40: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 40 / 94

Lock

● ReentrantLock● verrou d'exclusion mutuel standard

– le verrou n'est 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 d'avoir plusieurs consommateurs en lecture pour un producteur en écriture– optimisations sur les données accédées souvent en lecture

Page 41: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 41 / 94

Condition

● Une condition est créée par l'instance de Lock● méthode newCondition()

● L'utilisation des conditions remplace l'utilisation des méthodes de gestion d'un moniteur Object● wait(), notify(), notifyAll()

● await() : met le thread propriétaire du lock en attente

● signal() : réveille le thread en attente suite à un await()

Page 42: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 42 / 94

Lock et Condition

● Dans l'exemple suivant● si take() est invoqué sur un buffer vide, le thread est

mis en attente jusqu'à ce que des items soient disponibles

● de même si put() est invoqué sur un buffer plein, le thread est mis en attente jusqu'à ce qu'il y ait de la place pour au moins un item

Page 43: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 43 / 94

Lock et Condition

class 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

Page 44: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 44 / 94

Lock et Condition

class 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

Page 45: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 45 / 94

Concurrence

● Reportez-vous à l'atelier 2

Page 46: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 46 / 94

Volatile

● Chaque thread possède un cache local● Le mot clé volatile permet de s'assurer qu'une

variable utilisée par plusieurs thread sera toujours à jour● la JVM rafraîchira le contenu de la variable à chaque

fois qu'elle est utilisée– la variable ne sera pas mise dans le cache local des Threads

● attention : voir la prise en compte de volatil par l'implémentation de la JVM

Page 47: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 47 / 94

ThreadLocal

● Permet à des threads exécutant le même code run() 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 de

variable 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() si aucun set() n'a été appelé

– void remove() retire la valeur associée au thread

Page 48: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 48 / 94

Communication entre threads

● Certains flux Java permettent la communication entre threads● un thread sera producteur d'octets ou de char

– classes PipedOutputStream et PipedWriter

● un thread sera consommateur d'octets ou char– classes PipedInputStream et PipedReader

Page 49: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 49 / 94

Communication entre threads

● Reportez-vous à l'atelier 3

Page 50: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 50 / 94

Tâches

● Planification de tâches par la classe Timer● toutes les tâches tournent dans un même thread

– schedule() et scheduleAtFixedRate() pour planifier une 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 de TimerTask– run() pour le code de la tâche

Page 51: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 51 / 94

CountDownLatch

● Permet de retarder l'exécution des threads tant qu'une opération n'est pas terminée● une fois loquet dans son état terminal ouvert, il ne peut

plus changer d'état● exemple :

– garanti qu'un calcul ne sera pas lancé tant que toutes les ressources nécessaires n'auront pas étés initialisées

– garanti qu'un service ne sera pas lancé tant que tous les services dépendant ne sont pas activés

Page 52: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 52 / 94

CountDownLatch

● La méthode await() permet de bloquer les threads jusqu'à ce que le loquet soit ouvert● CountDownLatch(int count) : crée le loquet avec

un certains nombre de tours● void await() : mise en attente tant que le compteur

n'est pas nul● void countDown() : décrémente le compteur

● long getCount() : renvoie le compteur

Page 53: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 53 / 94

CountDownLatch

● Exemple d'attente 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 %s\n", Thread.currentThread().getName());Tread.sleep(delay);

} catch (InterruptedException e) {e.printStackTrace();

} finally {latch.countDown();System.out.printf(">>> END %s countDown==%d\n",

Thread.currentThread().getName(), latch.getCount());}

}}

Page 54: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 54 / 94

CountDownLatch

● Exemple d'attente 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");

}

}

Page 55: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 55 / 94

CountDownLatch

● Reportez vous à l'atelier 4

Page 56: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 56 / 94

CyclicBarrier

● Permet de définir un point d'attente à plusieurs threads● la barrière est débloquées lorsque tous les processus

enregistrés ont atteint ce point● par rapport au loquet

– le loquet est éphémère, une fois ouvert il ne peu plus être utilisé

– un loquet attend des événements, tandis que une barrière attends d'autres threads

Page 57: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 57 / 94

CyclicBarrier

● CyclicBarrier(int parts) : création d'une barrière avec un certain nombre de participants

● CyclicBarrier(int parts,Runnable barrierAction)

création d'une barrière avec un certain nombre de participants et lancement d'une action lorsque la barrière est ouverte

● int await() : permet au thread de s'enregistrer auprès de la barrière, l'appel est bloquant tant que les autres threads participants n'ont pas fini

Page 58: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 58 / 94

CyclicBarrier

● Exemple d'attente avant lancement d'un autre thread● chaque tâche additionne une ligne d'une matrice● lorsque toutes les tâches sont finies une addition de

chaque ligne est effectuée

private static int matrix[][] = { { 1 }, { 2, 2 }, { 3, 3, 3 },{ 4, 4, 4, 4 }, { 5, 5, 5, 5, 5 } };

Page 59: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 59 / 94

CyclicBarrier

● Exemple d'attente avant lancement d'un autre thread

public 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 seront terminées

création de la barrière avecnombre de tâches et threadà lancer lorsque la barrièresera ouverte

Page 60: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 60 / 94

CyclicBarrier● Exemple d'attente avant lancement d'un 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

Page 61: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 61 / 94

CyclicBarrier

● Reportez-vous à l'atelier 5

Page 62: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 62 / 94

Exchanger

● Exchanger<V> : forme de barrière formée de deux 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 buffer

vide● l'échange est provoqué dès que les deux threads

appel la méthode V exchange(V x)

Page 63: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 63 / 94

Exchanger

● Exemple d'échange de String

public 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 String

on passe l'échangeur aux 2 threads

Page 64: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 64 / 94

Exchanger

● 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

Page 65: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 65 / 94

Exchanger

● Reportez-vous à l'atelier 6

Page 66: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 66 / 94

Semaphore

● Encapsule un entier● contrainte de positivité● opérations d'incrémentation et de décrémentation

atomiques

● Gère un ensemble de jetons virtuels● le nombre initial de jeton est passé au constructeur de Semaphore

● acquire() : l'activité prend un jeton, appel bloquant

● release() : l'activité rend le jeton

Page 67: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 67 / 94

Semaphore

● Constructeurs● Semaphore(int permits, boolean fair) créer

le sémaphore en précisant le nombre de jetons et la distribution des jetons dans l'ordre des demandes

● Semaphore(int permits) créer le sémaphore en précisant le nombre de jetons, sans garantie de distribution dans l'ordre des demandes– équivalent à Semaphore(int permits,false)

Page 68: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 68 / 94

Semaphore

● Permet d'implé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 d'un jetonmise en attente si pas de jeton disponible

Page 69: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 69 / 94

Semaphore

● Permet d'implé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 d'un jetonmise en attente si pas de jeton disponible

Page 70: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 70 / 94

Exécution de tâches

● JDK 1.5 met à disposition des exécuteurs de tâches● interface Executor : découple les appels de tâche

de leur exécution, en précisant l'utilisation des threads, leur ordonnancement, …

● interface ExecutorService : gestion des tâches asynchrones– permet l'utilisation de méthodes de terminaison de

processus, cf. interface Future

● interface ScheduleExecutorService : gestion de tâches périodiques

Page 71: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 71 / 94

Exécution de tâches

● Les exemples suivants utilisent la classe RunnableTask

public 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());

}}

Page 72: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 72 / 94

Exé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");

}}

Page 73: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 73 / 94

Exécution de tâches

● Résultat de l'exécution des tâches sur un seul thread

>>> 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

Page 74: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 74 / 94

Exé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");}

}

Page 75: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 75 / 94

Exécution de tâches

● Résultat de l'exécution des tâches sur un seul thread

>>> 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

Page 76: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 76 / 94

Tâches asynchrones

● Future● interface représentant le traitement résultat d'un

traitement asynchrone● instances créées par ExecutorService

● Callable● permet le retour d'une valeur après l'exécution d'une

tâche– ce que ne permet pas la méthode run() de Runnable

● le callable est soumis à un exécuteur, le framework retourne un Future

Page 77: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 77 / 94

Tâches asynchrones

● Exemple de Callable

public 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;

}}

Page 78: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 78 / 94

Tâches asynchrones● Exemple d'utilisation de Future

public 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);

}}

Page 79: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 79 / 94

Tâches asynchrones

● Reportez-vous à l'atelier 7

Page 80: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 80 / 94

Java 6 - ajouts

● Deux types de collections sont ajoutées● Deque : file à double entrée

– garanti les insertions et suppression efficaces aux deux extrémités

– implémenté par ArrayDeque et LinkedBlockingDeque

● adaptées au pattern "Vol de tâche"– le consommateur – producteur utilise une seule file de

tâches partagées par tous les consommateurs– le vol de tâche utilise un file double par consommateur, un

consommateur ayant épuisé sa file peut voler la tâche à la fin d'une file double d'un autre

Page 81: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 81 / 94

Java 7 : ajouts

● TransferQueue

● interface modélisant une file d'attente bloquante– le producteur attend que le consommateur prenne ce qu'il a mis

dans 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 un nombre de tâches enregistrées pouvant varier durant l'exécution

Page 82: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 82 / 94

Java 7 : fork/join

● Problème de base : traiter de grandes quantités de données paquet par paquet● chaque paquet peut être traiter de manière indépendante

des 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 d'un tableau en sous-tableau● dynamique : découverte d'une arborescence d'un système

de fichier– quel volume de tâches à créer ?

Page 83: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 83 / 94

Java 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 de

synchronisation type CyclicBarrier● utiliser le traitement parallèle avec ForkJoinTask

Page 84: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 84 / 94

Java 7 : fork/join

● Deux classes de base● ForkJoinTask

– modélise une tâche unique qui sera envoyée à une réserve de threads

– peut générer d'autres tâches du même type qui seront envoyé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 qu'un grand nombre de tâches

élémentaires soit traitées par un nombre restreint de threads

Page 85: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 85 / 94

Java 7 : fork/join

● La machine qui exécute la tâche doit posséder plusieurs processeurs

● La tâche est récursive● RecursiveTask : avec renvoi de résultat

● RecursiveAction : sans renvoi de résultat

● Algorithme de base d'utilisation du framework fork/join :

if (my portion of the work is small enough) do the work directlyelse split my work into two pieces invoke the two pieces and wait for the results

Page 86: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 86 / 94

Java 7 : fork/join

● La javadoc précise qu'une tâche élémentaire● ne doit pas comporter de synchronisation afin d'éviter

les blocages● ne doivent pas partager de variables● doivent pouvoir être exécutées rapidement

Page 87: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 87 / 94

Java 7 : fork/join

● La javadoc précise qu'une tâche élémentaire● ne doit pas comporter de synchronisation afin d'éviter

les blocages● ne doivent pas partager de variables● doivent pouvoir être exécutées rapidement

Page 88: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 88 / 94

Java 7 : fork/join

ForkJoinPoolForkJoinPool

Tâche longues'occupe du découpage

en sous tâches

Tâche longues'occupe du découpage

en sous tâches

lance la tâche

sous-tâche sous-tâche sous-tâche

sous-tâche

sous-tâche

sous-tâche sous-tâche

sous-tâche

fork()

join()

Page 89: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 89 / 94

Java 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 n'est pas finie

– fork() : lance une autre tâche dans la même réserve de pool que la tâche courante

● une même tâche ne doit pas appeler plus d'une fois sa méthode fork()

● spécialisée par RecusiveAction et RecursiveTask<V>– compute() : méthode exécutée par la tâche

Page 90: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 90 / 94

Java 7 : fork/join

● Reportez-vous à l'atelier 8

Page 91: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 91 / 94

Objets immuables

● La classe doit être déclarée final● pour éviter la modification d'une 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 ;

Page 92: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 92 / 94

Objets immuables

● Les propriétés référençant des objets non immuables doivent :● être privées● ne jamais être exportées● représenter l'unique référence à l'objet

– faire des copies défensives

Page 93: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 93 / 94

Objets immuables

private 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ée

private final Date theDate;

public MaClasse(Date theDate) { this.theDate = (Date) theDate.clone();}

copie défensive

Page 94: Java - programmation concurrente

antislashn.org Java avancé - Programmation concurrente 2 - 94 / 94

Ressources

● Livres

● Java Threads– auteurs : Scott Oaks, Henry Wong

– éditeur : O'Reilly

● 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/