Quel est l’objetde la programmation   concurrente ?
Tirer parti de lapuissance des processeurs
1) De quoi cette puissance est-elle faite ?      Architectures muticœurs2) Conséquences sur la façon de coder ?3) Quels so...
5) De quels outils dispose-t-on ?  Java 6  Java 7  Java 86) Importance de l’algorithmique ?
MULTITHREADING
1995
1995
1995Si un thread a « asser travaillé »S’il est en attente d’une ressource lenteS’il est en attente d’un autre thread
Parallèle                           1995 SIMD : chaque CPU travaille sur ses propres    données
API Java                               1995•   Thread, Runnable•   Threads « natifs », « Green threads »•   Moniteur•   sy...
API Java                               1995•   Thread, Runnable•   Threads « natifs », « Green threads »•   Moniteur•   sy...
2004 - 2005       Software       Hardware
Processeurs multicœurs• Fin de la « soupe gratuite »• La puissance de calcul augmente  par le nombre de cœurs, et non  plu...
Processeurs multicœurs• Aujourd’hui  – Smartphone : 2 à 4 cœurs  – PC de bureau : 4 à 8 cœurs  – Serveur pro : 128 cœurs• ...
Java.util.concurrent• API de concurrence avancée  – Dispo en Java 4 EDU.oswego• Nouvelle approche du multithreading  – Nou...
Problèmes dumultithread ?
1) Il est nécessaire !
2) Data raceDeux threads modifient une variable        « en même temps »
public class Singleton {    private static Singleton instance ;    private Singleton() {}    public static Singleton getIn...
Interruption                                              =public class Singleton {    public class Singleton {           ...
public class Singleton {    private static Singleton instance ;    private Singleton() {}    public static synchronized Si...
Lecture                                           ralentiepublic class Singleton {    public class Singleton {    private ...
Doublepublic class Singleton {                                     check locking    private static Singleton instance ;   ...
Doublepublic class Singleton {                                     check locking    private static Singleton instance ;   ...
public enum Singleton {    instance ;}
Solutions aux « data races »• Synchronisation de la modification des  variables     « garder les variables »• Et si on ne ...
SYNCHRONISATION
Java Memory Model• Objet : définir la valeur d’une variable à un  instant donné• Règle : « toute lecture d’une variable  r...
Java Memory Model• Objet : définir la valeur d’une variable à un  instant donné• Règle : « toute lecture d’une variable  r...
Java Memory Model• Objet : définir la valeur d’une variable à un  instant donné• Règle : « toute lecture d’une variable  r...
Java Memory Model• Multithread multicœur : vrai problème !« toute lecture … retourne  la dernière valeur écrite … »• Chron...
Happens before• Chronologie = créer des liens entre les  lectures et les écritures             x = 1                      ...
Happens before• Chronologie = créer des liens entre les  lectures et les écritures             x = 1                      ...
Happens before• Règle :    Un lien « happens before » est établi    entre toute écriture synchronisée ou    volatile et to...
private int index ;public void incrementonsGaiement() {    index++ ;}public void testonsJoyeusement() {    if (index > 10)...
Pas de lien                                « happens before »private int index ;public void incrementonsGaiement() {    in...
private volatile int index ;public void incrementonsGaiement() {    index++ ;}public void testonsJoyeusement() {    if (in...
Lien                                « happens before »private volatile int index ;public void incrementonsGaiement() {    ...
Cas pathologique               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMethode...
1) T1 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
1) T1 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
1) T1 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
1) T2 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
1) T2 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
1) T2 prend le lock               private int x, y, r1, r2 ;               private Object lock = new Object() ;void maMeth...
Doublepublic class Singleton {                                     check locking    private static Singleton instance ;   ...
Variable volatile !public class Singleton {    private volatile static Singleton instance ;    public static Singleton get...
PROCESSEUR
private Object o = new Object() ;private int index = 0 ;public void uneMethode() {    synchronized (o) {       index++ ;  ...
private Object o = new Object() ;private int index = 0 ;public void uneMethode() {    synchronized (o) {       index++ ;  ...
private Object o = new Object() ;private int index = 0 ;public void uneMethode() {    synchronized (o) {       index++ ;  ...
« Visibilité »
Barrière de mémoire• Une instruction assembleur• Permet de « propager » une modification  d’un cœur à l’autre• Invalide le...
Optimisation 1Concevoir des traitements tels que :• Les données tiennent dans 32kO• Le code tient dans 32kO• Et pas de bar...
Optimisation 2• S’arranger pour placer ses données dans  des zones contigües de la mémoire ⇒ Divise pas 8 les temps de cha...
Cadeau empoisonné de L3• Le cache invalide les données ligne par ligne• Cas de deux threads :   – Le premier exécute une m...
Cadeau empoisonné de L3• Catastrophique pour les perf !• Solution : recours au « variable padding »• Utilisé dans le disru...
public class Sequence {    private static final AtomicLongFieldUpdater<Sequence> updater =         AtomicLongFieldUpdater....
Conclusion• Prendre en compte le processeur   – Permet de belles optimisations   – Délicat à utiliser !     • Tenir compte...
Conclusion• Prendre en compte le processeur   – Permet de belles optimisations   – Délicat à utiliser !     • Tenir compte...
java.util.concurrent
Nouvelle façon delancer les threads
La manière du JDK 1.1Runnable r = new Runnable() {      public void run() {          while (true) {            System.out....
La manière du JDK 1.1Runnable r = new Runnable() {      public void run() {          while (true) {            System.out....
La manière du JDK 5ExecutorService service =    new ScheduledThreadPoolExecutor(10) ;Callable<Boolean> task = new Callable...
Nouvelle façon de  synchroniser
Interface Lockprivate Lock lock = new ReentrantLock() ;public void maMethode() {      lock.lock() ; // bloque « comme » sy...
Interface Lockprivate Lock lock = new ReentrantLock() ;public void maMethode() {      lock.tryLock(10, TimeUnit.MILLISECON...
Classe Semaphoreprivate Semaphore s = new Semaphore(5) ;public void maMethode() {      s.acquire() ; // bloque « comme » s...
Classe Semaphoreprivate Semaphore s = new Semaphore(5) ;public void maMethode() {      s.tryAcquire(10, TimeUnit.MILLISECO...
Classe Semaphore• Deux méthodes supplémentaires :  availablePermits()  getQueueLength()
Classe CountDownLatch• Utilisable en initialisation (pas de reset)private CountDownLatch latch = new CountDownLatch() ;pub...
Classe CyclicBarrier • Synchronisation sur la fin du traitement de   plusieurs tâchesprivate CyclicBarrier barrier = new C...
Interface ReadWriteLock• Gère des paires de Lock   – Un pour la lecture   – Un pour l’écriture• Lecture : concurrence poss...
Interface ReadWriteLockprivate ReadWriteLock rwLock = new ReentrantReadWriteLock() ; • Pas de contrainte sur les lecturesp...
Interface ReadWriteLock • Les écritures stoppent les lectures • Une seule écriture à la foisprivate ReadWriteLock rwLock =...
Types atomiques
Types atomiques• AtomicLong, AtomicFloat, etc…private AtomicInteger index = new AtomicInteger(0) ;public void uneMethode()...
Types atomiques• Principe du CAS « compare and swap »• Prend en entrée :   – Une adresse mémoire   – Deux valeurs « ancien...
Types atomiques// classe AtomicLongpublic final long incrementAndGet() {    for (;;) {        long current = get() ;      ...
Files d’attente• BlockingQueue   – File d’attente de taille fixe   – add(e), offer(e), put(e) avec timeout   – remove(e), ...
Tableau immutable• CopyOnWriteArrayList (et version LinkedList)  – Lecture synchronisée  – Écriture par duplication• Le ta...
Structures immutables• Peut-on construire d’autres structures  immutables dans l’API Collection ?   – Tables de hachage• R...
Alternatives àsynchronized
STMSoftware Transactionnal memory
Philisophie• Base de données :begin    update ... set ... where ...commit• Sur le commit :   – Succès : on continue   – Éc...
Même chose dans la JVM ?• Plusieurs implémentations• Akka 1.3.1    <dependency>       <groupId>se.scalablesolutions.akka</...
Pattern STM                             Effectué dans                                       une transaction final Ref<Inte...
Pattern STM                           Exécuté dans le                                      thread courant final Ref<Intege...
Pattern STM• Une transaction qui échoue est rejouée  (idem AtomicLong)   – Utilisation du processeur différente de la     ...
Pattern STM• Bons cas applicatifs : faible concurrence  d’accès• Forte concurrence : les cœurs passent leur  temps à rejou...
Implémentation des STM• Peut utiliser les Locks• Peut ne pas les utiliserDans ce cas : quid de la visibilité (pas de barri...
Implémentation des STM• Consomme des ressources (mémoire)   – Fonction du nombre de transactions   – Peut être en O(n2) (t...
Futur des STM• Architecture Haswell d’Intel (2013)  – Support de TSX (Transactional    Synchronisation Extension)  – TSX p...
Acteurs
Modèle d’acteurs1973• Un acteur réalise un traitement• Il reçoit un message immutable• Effectue un traitement, et retourne...
Modèle d’acteurs• Utilisé en Erlang• Plusieurs API Java et sur la JVM (Scala,  Clojure)Akka : écrit en Scala
Akka : fonctionnement• Akka gère un pool de threads• On crée des acteurs, on leur envoie des  messages• Un message reçu es...
4000! – Akkapublic class PrimeFinderActor extends UntypedActor {    public void onReceive(Object o) throws Exception {    ...
4000! - ExecutorServicepublic class PrimeFactorCallableimplements Callable<PrimeFactors> {    private int debut, fin ;    ...
public static void main(String[] args) {    Future [] futures = new Future [400] ;    for (int i = 0 ; i < futures.length ...
public static void main(String... args)    throws ExecutionException, InterruptedException {    ExecutorService es = new S...
[2^3989][3^1996][5^996][7^664][11^399][13^331][17^248][19^221][23^180][29^141][31^133][37^110][41^99][43^95][47^86][53^76]...
Performances• Les codes se ressemblent• Utilisation CPU : idem• Temps de calcul :   – Akka : 2,7s   – ExecutorService : 2,...
Exécution transactionnelle     public class Balance {         public final int montant ;         public Balance(int montan...
Exécution transactionnelle     public class Depot {         public final int montant ;         public Depot(int montant) {...
Exécuté dans                                                      une transactionpublic class CompteBancaire extends Untyp...
Fera échouer la                                                        transactionpublic class CompteBancaire extends Unty...
public class Transfert {    public final ActorRef source ;    public final ActorRef destination ;    public final int mont...
Ensemble d’appels                                                d’acteurspublic class ServiceBancaire extends UntypedTran...
Ensemble d’appels                                                d’acteurspublic class ServiceBancaire extends UntypedTran...
Appel dans une                                                transactionpublic class ServiceBancaire extends UntypedTrans...
Exécution transactionnelle• Chaque acteur gère un compte• Il possède un état, mais qui n’est jamais  partagé• Les transfer...
Bilan STM & acteurs• STM & acteurs : deux approches  alternatives à synchronized• Offrent des fonctionnalités  supplémenta...
Parallélisation des     calculs
Nouveautés Java 7 & 8• Pattern Fork / Join• API non incluse en Java 7 : parallel arrays• Méthode en Java 8 : parallel()Obj...
Java 7 : fork / join
Fork / Join• Traite des calculs sur de grandes quantités  de données, numériques ou non• Gère des tâches   – Si elle est t...
Fork / Join• Gère un pool de threads• Chaque thread possède une file d’attente  qui stocke les tâches• Quand sa file d’att...
Fork / Join• Chaque tâche travaille sur ses propres  données• Pas de bloc synchronisé• Pas de variables partagées• On doit...
Parallel Arrays  Java 6 &7
Parallel Arrays•   API non incluse dans le JDK•   Peut être utilisée en Java 6•   Fork / Join dans un package jsr166y.*•  ...
Pourquoi les parallel arrays   ne sont-ils pas dans       l’API Java 7 ?
Java 8Sept. 2013
Syntaxe  • Du light !int maxAge =       persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = ...
Syntaxe                               Type Collection  • Du light !int maxAge =       persons.map(p -> p.getAge()).reduce(...
Syntaxe                              D’où viennent les                                       méthodes map()               ...
Syntaxe  • Du light !int maxAge =       persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = ...
Méthodes virtuelles d’ext.• On ajoute des méthodes dans les interfaces,  avec leurs implémentation par défaut  public inte...
Syntaxe  • Du light !int maxAge =       persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = ...
Interface spliterable()• Extension d’iterable()• Type de retour de parallel()• Le fork / join devient un framework système...
Algorithmique
Une anecdoteLe 24/2/2012 Heinz Kabutz  lance un défi :• Déterminer les 10 premiers et  10 derniers octets du nombre  Fibon...
Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs
Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs• 1ère amélioration : 3300s sur un CPU 4  cœurs
Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs• 1ère amélioration : 3300s sur un CPU 4  cœurs• 2ème amélioration...
Une anecdotePar quel miracle ?• Utilisation de GNU Multiple Precision  Arithmetic Lib (GMP)• Changement d’implémentation d...
Par quel miracle ?      Quel rapport avec• Utilisation de GNU Multiple Precision  Arithmetic Lib (GMP)• Changement d’implé...
AlgorithmiqueL’optimisation des fonctions linéaires a gagné  un facteur 43M sur les temps de traitement  en 15 ans :• 1k e...
Moralité• Utiliser les bons algorithmes de traitement  avant de penser à la parallélisation
Moralité• Utiliser les bons algorithmes de traitement  avant de penser à la parallélisation• S’assurer que les algorithmes...
Moralité• Utiliser les bons algorithmes de traitement  avant de penser à la parallélisation• S’assurer que les algorithmes...
Moralité• Utiliser les bons algorithmes de traitement  avant de penser à la parallélisation• S’assurer que les algorithmes...
Conclusion
ConclusionUne nouvelle période charnière se déroule en  ce momentEn 1995 : la mémoire est devenue une  ressource gérée par...
ConclusionLes applications vont utiliser des traitements  en parallèle de façon transparenteMais les pièges se trouvent au...
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
Upcoming SlideShare
Loading in...5
×

De Runnable & synchronized à parallele() et atomically()

915

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
915
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

De Runnable & synchronized à parallele() et atomically()

  1. 1. Quel est l’objetde la programmation concurrente ?
  2. 2. Tirer parti de lapuissance des processeurs
  3. 3. 1) De quoi cette puissance est-elle faite ? Architectures muticœurs2) Conséquences sur la façon de coder ?3) Quels sont les problèmes des applications « parallèles » ? Synchronisation4) Comment s’y prendre pour « synchroniser » les opérations
  4. 4. 5) De quels outils dispose-t-on ? Java 6 Java 7 Java 86) Importance de l’algorithmique ?
  5. 5. MULTITHREADING
  6. 6. 1995
  7. 7. 1995
  8. 8. 1995Si un thread a « asser travaillé »S’il est en attente d’une ressource lenteS’il est en attente d’un autre thread
  9. 9. Parallèle 1995 SIMD : chaque CPU travaille sur ses propres données
  10. 10. API Java 1995• Thread, Runnable• Threads « natifs », « Green threads »• Moniteur• synchronized, volatile
  11. 11. API Java 1995• Thread, Runnable• Threads « natifs », « Green threads »• Moniteur• synchronized, volatile 2004
  12. 12. 2004 - 2005 Software Hardware
  13. 13. Processeurs multicœurs• Fin de la « soupe gratuite »• La puissance de calcul augmente par le nombre de cœurs, et non plus par l’augmentation de la fréquence de chaque cœur• Apparition des GPGPU (2007)
  14. 14. Processeurs multicœurs• Aujourd’hui – Smartphone : 2 à 4 cœurs – PC de bureau : 4 à 8 cœurs – Serveur pro : 128 cœurs• Demain – Plateforme exascale : de 100k à 1M nœuds – Chaque nœud : de 1k à 10k cœurs
  15. 15. Java.util.concurrent• API de concurrence avancée – Dispo en Java 4 EDU.oswego• Nouvelle approche du multithreading – Nouvelle façon de lancer des threads – Nouvelle façon de synchroniser les opérations
  16. 16. Problèmes dumultithread ?
  17. 17. 1) Il est nécessaire !
  18. 18. 2) Data raceDeux threads modifient une variable « en même temps »
  19. 19. public class Singleton { private static Singleton instance ; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton() ; } return instance ; }}
  20. 20. Interruption =public class Singleton { public class Singleton { catastrophe private static Singleton instance ; private static Singleton instance ; private Singleton() {} private Singleton() {} public static Singleton getInstance() { public static Singleton getInstance() { if (instance == null) { if (instance == null) { instance = new Singleton() ; instance = new Singleton() ; } } return instance ; return instance ; } } }}
  21. 21. public class Singleton { private static Singleton instance ; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton() ; } return instance ; }}
  22. 22. Lecture ralentiepublic class Singleton { public class Singleton { private static Singleton instance ; private static Singleton instance ; private Singleton() {} private Singleton() {} public static Singleton getInstance() { public static synchronized Singleton getInstance() { if (instance == null) { if (instance == null) { instance = new Singleton() ; instance = new Singleton() ; } } return instance ; return instance ; } } }}
  23. 23. Doublepublic class Singleton { check locking private static Singleton instance ; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton() ; } } } return instance ; }}
  24. 24. Doublepublic class Singleton { check locking private static Singleton instance ; BUG ! public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton() ; } } } return instance ; }}
  25. 25. public enum Singleton { instance ;}
  26. 26. Solutions aux « data races »• Synchronisation de la modification des variables « garder les variables »• Et si on ne modifie jamais nos variables ? Systèmes immutables
  27. 27. SYNCHRONISATION
  28. 28. Java Memory Model• Objet : définir la valeur d’une variable à un instant donné• Règle : « toute lecture d’une variable retourne la dernière valeur écrite dans cette variable »
  29. 29. Java Memory Model• Objet : définir la valeur d’une variable à un instant donné• Règle : « toute lecture d’une variable retourne la dernière valeur écrite dans cette variable »• Monothread : contrainte sur le fonctionnement des compilateurs & de la JVM
  30. 30. Java Memory Model• Objet : définir la valeur d’une variable à un instant donné• Règle : « toute lecture d’une variable retourne la dernière valeur écrite dans cette variable »• Multithread multicœur : vrai problème !« toute lecture … retourne la dernière valeur écrite … »
  31. 31. Java Memory Model• Multithread multicœur : vrai problème !« toute lecture … retourne la dernière valeur écrite … »• Chronologie entre les threads / cœurs
  32. 32. Happens before• Chronologie = créer des liens entre les lectures et les écritures x = 1 r1 = x• Valeur de r1 ? – Même thread ⇒ évident – Threads différents : impossible de prévoir
  33. 33. Happens before• Chronologie = créer des liens entre les lectures et les écritures x = 1 happens before r1 = x• Valeur de r1 ? – Imposée par la JLS : r1 = 1
  34. 34. Happens before• Règle : Un lien « happens before » est établi entre toute écriture synchronisée ou volatile et toute lecture synchronisée ou volatile qui suit• Existence de ce lien ⇒ Javadoc (java.util.concurrent)
  35. 35. private int index ;public void incrementonsGaiement() { index++ ;}public void testonsJoyeusement() { if (index > 10) { System.out.println("Index est grand !") ; }}
  36. 36. Pas de lien « happens before »private int index ;public void incrementonsGaiement() { index++ ;}public void testonsJoyeusement() { if (index > 10) { System.out.println("Index est grand !") ; }}
  37. 37. private volatile int index ;public void incrementonsGaiement() { index++ ;}public void testonsJoyeusement() { if (index > 10) { System.out.println("Index est grand !") ; }}
  38. 38. Lien « happens before »private volatile int index ;public void incrementonsGaiement() { index++ ;}public void testonsJoyeusement() { if (index > 10) { System.out.println("Index est grand !") ; }}
  39. 39. Cas pathologique private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { r1 = y ; y = 1 ; } } r2 = x ;} }
  40. 40. 1) T1 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { y = 1 ; 2 } r1 = y ; } r2 = x ;} }
  41. 41. 1) T1 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { y = 1 ; 2 } r1 = y ; } 3 r2 = x ;} } 4
  42. 42. 1) T1 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { y = 1 ; 2 } r1 = y ; } 3 r2 = x ;} } 4 r2 = 1
  43. 43. 1) T2 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { r1 = y ; y = 1 ; } } r2 = x ;} } 4
  44. 44. 1) T2 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { r1 = y ; y = 1 ; ? ? } } r2 = x ;} } 4
  45. 45. 1) T2 prend le lock private int x, y, r1, r2 ; private Object lock = new Object() ;void maMethode() { 1 void maMethodeAussi() { x = 1 ; synchronized(lock) { synchronized(lock) { r1 = y ; y = 1 ; ? ? } } r2 = x ;} } 4 r2 = 0 ? r2 = 1 ?
  46. 46. Doublepublic class Singleton { check locking private static Singleton instance ; Lecture non public static Singleton synchronisée getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton() ; } } } return instance ; }}
  47. 47. Variable volatile !public class Singleton { private volatile static Singleton instance ; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton() ; } } } return instance ; }}
  48. 48. PROCESSEUR
  49. 49. private Object o = new Object() ;private int index = 0 ;public void uneMethode() { synchronized (o) { index++ ; }}
  50. 50. private Object o = new Object() ;private int index = 0 ;public void uneMethode() { synchronized (o) { index++ ; }}
  51. 51. private Object o = new Object() ;private int index = 0 ;public void uneMethode() { synchronized (o) { index++ ; }}
  52. 52. « Visibilité »
  53. 53. Barrière de mémoire• Une instruction assembleur• Permet de « propager » une modification d’un cœur à l’autre• Invalide le cache L1, force sa relecture dans L3 ou la mémoire
  54. 54. Optimisation 1Concevoir des traitements tels que :• Les données tiennent dans 32kO• Le code tient dans 32kO• Et pas de barrière de mémoire ⇒ Exécution à 1GHz
  55. 55. Optimisation 2• S’arranger pour placer ses données dans des zones contigües de la mémoire ⇒ Divise pas 8 les temps de chargement
  56. 56. Cadeau empoisonné de L3• Le cache invalide les données ligne par ligne• Cas de deux threads : – Le premier exécute une méthode, accède àa – Le second exécute une autre méthode, accède à b• Pas de concurrence d’accès sur a et b
  57. 57. Cadeau empoisonné de L3• Catastrophique pour les perf !• Solution : recours au « variable padding »• Utilisé dans le disruptor (LMAX)
  58. 58. public class Sequence { private static final AtomicLongFieldUpdater<Sequence> updater = AtomicLongFieldUpdater.newUpdater(Sequence.class, "value"); private volatile long p1 = 7L, p2 = 7L, p3 = 7L, p4 = 7L, p5 = 7L, p6 = 7L, p7 = 7L ; private volatile long value = Sequencer.INITIAL_CURSOR_VALUE ; private volatile long q1 = 7L, q2 = 7L, q3 = 7L, q4 = 7L, q5 = 7L, q6 = 7L, q7 = 7L; // ... public long sumPaddingToPreventOptimisation() { return p1 + p2 + p3 + p4 + p5 + p6 + p7 + value + q1 + q2 + q3 + q4 + q5 + q6 + q7; } public void setPaddingValue(final long value) { p1 = p2 = p3 = p4 = p5 = p6 = p7 = q1 = q2 = q3 = q4 = q5 = q6 = q7 = value; }}
  59. 59. Conclusion• Prendre en compte le processeur – Permet de belles optimisations – Délicat à utiliser ! • Tenir compte de l’ordre des variables en mémoire
  60. 60. Conclusion• Prendre en compte le processeur – Permet de belles optimisations – Délicat à utiliser ! • Tenir compte de l’ordre des variables en mémoire• Veut-on le faire ?• Le langage est-il prêt ?
  61. 61. java.util.concurrent
  62. 62. Nouvelle façon delancer les threads
  63. 63. La manière du JDK 1.1Runnable r = new Runnable() { public void run() { while (true) { System.out.println("Vogue la galère !") ; } }} ;Thread t = new Thread(r) ;t.start() ;
  64. 64. La manière du JDK 1.1Runnable r = new Runnable() { public void run() { while (true) { System.out.println("Vogue la galère !") ; } }} ;Thread t = new Thread(r) ;t.start() ; 1) Pas de type de retour 2) Pas d’exception 3) Création / destruction
  65. 65. La manière du JDK 5ExecutorService service = new ScheduledThreadPoolExecutor(10) ;Callable<Boolean> task = new Callable<Boolean>() { public Boolean call() throws Exception { int i = 0 ; while (i++ < 1000) { System.out.println("Vogue la galère !") ; } return true ; } 1) Type de retour, exception}; 2) Cycle de vie géré par le poolFuture<Boolean> f = service.submit(task) ;Boolean b = f.get(100, TimeUnit.MILLISECONDS) ;
  66. 66. Nouvelle façon de synchroniser
  67. 67. Interface Lockprivate Lock lock = new ReentrantLock() ;public void maMethode() { lock.lock() ; // bloque « comme » synchronized // ... lock.unlock() ;} ;
  68. 68. Interface Lockprivate Lock lock = new ReentrantLock() ;public void maMethode() { lock.tryLock(10, TimeUnit.MILLISECONDS) ; // timeout // ... lock.unlock() ;} ;
  69. 69. Classe Semaphoreprivate Semaphore s = new Semaphore(5) ;public void maMethode() { s.acquire() ; // bloque « comme » synchronized // ... s.release() ;} ;
  70. 70. Classe Semaphoreprivate Semaphore s = new Semaphore(5) ;public void maMethode() { s.tryAcquire(10, TimeUnit.MILLISECONDS) ; // timeout // ... s.release() ;} ;
  71. 71. Classe Semaphore• Deux méthodes supplémentaires : availablePermits() getQueueLength()
  72. 72. Classe CountDownLatch• Utilisable en initialisation (pas de reset)private CountDownLatch latch = new CountDownLatch() ;public void init() { db.connect() ; // étape « lente » latch.countDown() ; // ouverture du latch} ;public void process() { latch.await() ; // attente de l’ouverture} ;
  73. 73. Classe CyclicBarrier • Synchronisation sur la fin du traitement de plusieurs tâchesprivate CyclicBarrier barrier = new CyclicBarrier(4) ;public void processOne() { // traitements divers barrier.await() ;} ;public void processTwo() { // traitements divers barrier.await() ;} ;
  74. 74. Interface ReadWriteLock• Gère des paires de Lock – Un pour la lecture – Un pour l’écriture• Lecture : concurrence possible• Écriture : exclusive• Visibilité des modifications garantie
  75. 75. Interface ReadWriteLockprivate ReadWriteLock rwLock = new ReentrantReadWriteLock() ; • Pas de contrainte sur les lecturesprivate ReadWriteLock rwLock = new ReentrantReadWriteLock() ;public void maMethodeQuiLit() { Lock readLock = rwLock.readLock() ; readLock.lock() ; // traitements de lecture readLock.unlock() ;} ;
  76. 76. Interface ReadWriteLock • Les écritures stoppent les lectures • Une seule écriture à la foisprivate ReadWriteLock rwLock = new ReentrantReadWriteLock() ;public void maMethodeQuiEcrit() { Lock writeLock = rwLock.writeLock() ; writeLock.lock() ; // traitements de lecture writeLock.unlock() ;} ;
  77. 77. Types atomiques
  78. 78. Types atomiques• AtomicLong, AtomicFloat, etc…private AtomicInteger index = new AtomicInteger(0) ;public void uneMethode() { long newValue = index.incrementAndGet() ;}• Compile en une unique instruction assembleur
  79. 79. Types atomiques• Principe du CAS « compare and swap »• Prend en entrée : – Une adresse mémoire – Deux valeurs « ancienne » & « nouvelle »• Si la valeur lue à l’adresse correspond à l’ancienne alors la nouvelle est recopiée• Sinon, retourne false• Pas de synchronisation !
  80. 80. Types atomiques// classe AtomicLongpublic final long incrementAndGet() { for (;;) { long current = get() ; long next = current + 1 ; if (compareAndSet(current, next)) return next ; }}
  81. 81. Files d’attente• BlockingQueue – File d’attente de taille fixe – add(e), offer(e), put(e) avec timeout – remove(e), poll(e), take(e) – element(e), examine(e)• Thread safe (locks internes) – Utilisable pour le pattern producteur / consommateur
  82. 82. Tableau immutable• CopyOnWriteArrayList (et version LinkedList) – Lecture synchronisée – Écriture par duplication• Le tableau lu n’est jamais modifié, donc on peut le partager sans synchronisation
  83. 83. Structures immutables• Peut-on construire d’autres structures immutables dans l’API Collection ? – Tables de hachage• Réponse : oui, et de façon efficace – Ce qui n’est pas le cas des tableaux
  84. 84. Alternatives àsynchronized
  85. 85. STMSoftware Transactionnal memory
  86. 86. Philisophie• Base de données :begin update ... set ... where ...commit• Sur le commit : – Succès : on continue – Échec : on annule les modifications – Règles de visibilité• Idée de 1986, implémentations 1995
  87. 87. Même chose dans la JVM ?• Plusieurs implémentations• Akka 1.3.1 <dependency> <groupId>se.scalablesolutions.akka</groupId> <artifactId>akka-kernel</artifactId> <version>1.3.1</version> </dependency> <repository> <id>Akka</id> <name>Akka Maven2 Repository</name> <url>http://akka.io/repository/</url> </repository>
  88. 88. Pattern STM Effectué dans une transaction final Ref<Integer> source = new Ref<Integer>(500) ; final Atomic<Object> atom = new Atomic<Object>() { @Override public Object atomically() { source.swap(source.get() + 1) ; return null ; } } ; atom.execute() ;
  89. 89. Pattern STM Exécuté dans le thread courant final Ref<Integer> source = new Ref<Integer>(500) ; final Atomic<Object> atom = new Atomic<Object>() { @Override public Object atomically() { source.swap(source.get() + 1) ; return null ; } } ; atom.execute() ;
  90. 90. Pattern STM• Une transaction qui échoue est rejouée (idem AtomicLong) – Utilisation du processeur différente de la synchronisation• Cas applicatifs non accessibles aux Locks Object o = queue1.remove() ; queue2.add(o) ;
  91. 91. Pattern STM• Bons cas applicatifs : faible concurrence d’accès• Forte concurrence : les cœurs passent leur temps à rejouer le code
  92. 92. Implémentation des STM• Peut utiliser les Locks• Peut ne pas les utiliserDans ce cas : quid de la visibilité (pas de barrière de mémoire)Visibilité : comment l’intégrité des données est-elle garantie ?
  93. 93. Implémentation des STM• Consomme des ressources (mémoire) – Fonction du nombre de transactions – Peut être en O(n2) (très mauvais)• Concurrence avec les Locks, qui n’en consomment pas
  94. 94. Futur des STM• Architecture Haswell d’Intel (2013) – Support de TSX (Transactional Synchronisation Extension) – TSX permet de marquer des portions de code – La mémoire modifiée n’est visible que du thread qui modifie cette mémoire – Elle est publiée « instantanément » sur commit
  95. 95. Acteurs
  96. 96. Modèle d’acteurs1973• Un acteur réalise un traitement• Il reçoit un message immutable• Effectue un traitement, et retourne éventuellement un résultatNon synchronisé car sans accès concurrent
  97. 97. Modèle d’acteurs• Utilisé en Erlang• Plusieurs API Java et sur la JVM (Scala, Clojure)Akka : écrit en Scala
  98. 98. Akka : fonctionnement• Akka gère un pool de threads• On crée des acteurs, on leur envoie des messages• Un message reçu est traité dans un thread• Un acteur ne peut pas être exécuté dans deux threads à la fois• Pas de concurrence d’accès sur son éventuel état
  99. 99. 4000! – Akkapublic class PrimeFinderActor extends UntypedActor { public void onReceive(Object o) throws Exception { List<Integer> bounds = (List<Integer>)o ; int debut = bounds.get(0) ; int fin = bounds.get(1) ; PrimeFactors pfs = new PrimeFactors() ; for (int i = debut ; i < fin ; i++) { PrimeFactors pfi = pfs.getPrimeFactors(i) ; pfs.add(pfi) ; } // return pfs ; getContext().reply(pfs) ; }}
  100. 100. 4000! - ExecutorServicepublic class PrimeFactorCallableimplements Callable<PrimeFactors> { private int debut, fin ; public PrimeFactorCallable(int debut, int fin) { this.debut = debut ; this.fin = fin ; } public PrimeFactors call() throws Exception { PrimeFactors pfs = new PrimeFactors() ; for (int i = debut ; i < fin ; i++) { PrimeFactors pfi = pfs.getPrimeFactors(i) ; pfs.add(pfi) ; } return pfs ; }}
  101. 101. public static void main(String[] args) { Future [] futures = new Future [400] ; for (int i = 0 ; i < futures.length ; i++) { List<Integer> bound = Collections.unmodifiableList( Arrays.asList(10*i, 10*(i + 1))) ; ActorRef primeFactorFinder = Actors.actorOf(PrimeFinderActor.class).start() ; futures[i] = primeFactorFinder.sendRequestReplyFuture(bound) ; } PrimeFactors pfs = new PrimeFactors() ; for (int i = 0 ; i < futures.length ; i++) { pfs.add((PrimeFactors)futures[i].get()) ; } Actors.registry().shutdownAll() ;}
  102. 102. public static void main(String... args) throws ExecutionException, InterruptedException { ExecutorService es = new ScheduledThreadPoolExecutor(10) ; Future [] futures = new Future [400] ; for (int i = 0 ; i < futures.length ; i++) { PrimeFactorCallable callable = new PrimeFactorCallable(10*i, 10*(i + 1)) ; futures[i] = es.submit(callable) ; } PrimeFactors pfs = new PrimeFactors() ; for (int i = 0 ; i < futures.length ; i++) { pfs.add((PrimeFactors)futures[i].get()) ; } es.shutdown() ;}
  103. 103. [2^3989][3^1996][5^996][7^664][11^399][13^331][17^248][19^221][23^180][29^141][31^133][37^110][41^99][43^95][47^86][53^76][59^68][61^66][67^59][71^56][73^54][79^50][83^48][89^44][97^41][101^39][103^38][107^37][109^36][113^35][127^31][131^30][137^29][139^28][149^26][151^26][157^25][163^24][167^23][173^23][179^22][181^22][191^20][193^20][197^20][199^20][211^18][223^17][227^17][229^17][233^17][239^16][241^16][251^15][257^15][263^15][269^14][271^14][277^14][281^14][283^14][293^13][307^13][311^12][313^12][317^12][331^12][337^11][347^11][349^11][353^11][359^11][367^10][373^10][379^10][383^10][389^10][397^10][401^9][409^9][419^9][421^9][431^9][433^9][439^9][443^9][449^8][457^8][461^8][463^8][467^8][479^8][487^8][491^8][499^8][503^7][509^7][521^7][523^7][541^7][547^7][557^7][563^7][569^7][571^7][577^6][587^6][593^6][599^6][601^6][607^6][613^6][617^6][619^6][631^6][641^6][643^6][647^6][653^6][659^6][661^6][673^5][677^5][683^5][691^5][701^5][709^5][719^5][727^5][733^5][739^5][743^5][751^5][757^5][761^5][769^5][773^5][787^5][797^5][809^4][811^4][821^4][823^4][827^4][829^4][839^4][853^4][857^4][859^4][863^4][877^4][881^4][883^4][887^4][907^4][911^4][919^4][929^4][937^4][941^4][947^4][953^4][967^4][971^4][977^4][983^4][991^4][997^4][1009^3][1013^3][1019^3][1021^3][1031^3][1033^3][1039^3][1049^3][1051^3][1061^3][1063^3][1069^3][1087^3][1091^3][1093^3][1097^3][1103^3][1109^3][1117^3][1123^3][1129^3][1151^3][1153^3][1163^3][1171^3][1181^3][1187^3][1193^3][1201^3][1213^3][1217^3][1223^3][1229^3][1231^3][1237^3][1249^3][1259^3][1277^3][1279^3][1283^3][1289^3][1291^3][1297^3][1301^3][1303^3][1307^3][1319^3][1321^3][1327^3][1361^2][1367^2][1373^2][1381^2][1399^2][1409^2][1423^2][1427^2][1429^2][1433^2][1439^2][1447^2][1451^2][1453^2][1459^2][1471^2][1481^2][1483^2][1487^2][1489^2][1493^2][1499^2][1511^2][1523^2][1531^2][1543^2][1549^2][1553^2][1559^2][1567^2][1571^2][1579^2][1583^2][1597^2][1601^2][1607^2][1609^2][1613^2][1619^2][1621^2][1627^2][1637^2][1657^2][1663^2][1667^2][1669^2][1693^2][1697^2][1699^2][1709^2][1721^2][1723^2][1733^2][1741^2][1747^2][1753^2][1759^2][1777^2][1783^2][1787^2][1789^2][1801^2][1811^2][1823^2][1831^2][1847^2][1861^2][1867^2][1871^2][1873^2][1877^2][1879^2][1889^2][1901^2][1907^2][1913^2][1931^2][1933^2][1949^2][1951^2][1973^2][1979^2][1987^2][1993^2][1997^2][1999^2][2003^1][2011^1][2017^1][2027^1][2029^1][2039^1][2053^1][2063^1][2069^1][2081^1][2083^1][2087^1][2089^1][2099^1][2111^1][2113^1][2129^1][2131^1][2137^1][2141^1][2143^1][2153^1][2161^1][2179^1][2203^1][2207^1][2213^1][2221^1][2237^1][2239^1][2243^1][2251^1][2267^1][2269^1][2273^1][2281^1][2287^1][2293^1][2297^1][2309^1][2311^1][2333^1][2339^1][2341^1][2347^1][2351^1][2357^1][2371^1][2377^1][2381^1][2383^1][2389^1][2393^1][2399^1][2411^1][2417^1][2423^1][2437^1][2441^1][2447^1][2459^1][2467^1][2473^1][2477^1][2503^1][2521^1][2531^1][2539^1][2543^1][2549^1][2551^1][2557^1][2579^1][2591^1][2593^1][2609^1][2617^1][2621^1][2633^1][2647^1][2657^1][2659^1][2663^1][2671^1][2677^1][2683^1][2687^1][2689^1][2693^1][2699^1][2707^1][2711^1][2713^1][2719^1][2729^1][2731^1][2741^1][2749^1][2753^1][2767^1][2777^1][2789^1][2791^1][2797^1][2801^1][2803^1][2819^1][2833^1][2837^1][2843^1][2851^1][2857^1][2861^1][2879^1][2887^1][2897^1][2903^1][2909^1][2917^1][2927^1][2939^1][2953^1][2957^1][2963^1][2969^1][2971^1][2999^1][3001^1][3011^1][3019^1][3023^1][3037^1][3041^1][3049^1][3061^1][3067^1][3079^1][3083^1][3089^1][3109^1][3119^1][3121^1][3137^1][3163^1][3167^1][3169^1][3181^1][3187^1][3191^1][3203^1][3209^1][3217^1][3221^1][3229^1][3251^1][3253^1][3257^1][3259^1][3271^1][3299^1][3301^1][3307^1][3313^1][3319^1][3323^1][3329^1][3331^1][3343^1][3347^1][3359^1][3361^1][3371^1][3373^1][3389^1][3391^1][3407^1][3413^1][3433^1][3449^1][3457^1][3461^1][3463^1][3467^1][3469^1][3491^1][3499^1][3511^1][3517^1][3527^1][3529^1][3533^1][3539^1][3541^1][3547^1][3557^1][3559^1][3571^1][3581^1][3583^1][3593^1][3607^1][3613^1][3617^1][3623^1][3631^1][3637^1][3643^1][3659^1][3671^1][3673^1][3677^1][3691^1][3697^1][3701^1][3709^1][3719^1][3727^1][3733^1][3739^1][3761^1][3767^1][3769^1][3779^1][3793^1][3797^1][3803^1][3821^1][3823^1][3833^1][3847^1][3851^1][3853^1][3863^1][3877^1][3881^1][3889^1][3907^1][3911^1][3917^1][3919^1][3923^1][3929^1][3931^1][3943^1][3947^1][3967^1][3989^1]
  104. 104. Performances• Les codes se ressemblent• Utilisation CPU : idem• Temps de calcul : – Akka : 2,7s – ExecutorService : 2,3s• Différence non significative
  105. 105. Exécution transactionnelle public class Balance { public final int montant ; public Balance(int montant) { this.montant = montant ; } } public class Retrait { public final int montant ; public Retrait(int montant) { this.montant = montant ; } }
  106. 106. Exécution transactionnelle public class Depot { public final int montant ; public Depot(int montant) { this.montant = montant ; } } public class GetBalance { }
  107. 107. Exécuté dans une transactionpublic class CompteBancaire extends UntypedTransactor { private final Ref<Integer> balance = new Ref<Integer>(0) ; public void atomically(final Object message) { if (message instanceof Depot) { int montant = ((Depot)message).montant ; if (montant > 0) balance.swap(balance.get() + montant) ; } if (message instanceof Retrait) { int montant = ((Retrait)message).montant ; if (montant > 0) { if (balance.get() < montant) throw new IllegalStateException("...") ; balance.swap(balance.get() - montant) ; } } if (message instanceof GetBalance) getContext().replySafe((new Balance(balance.get()))) ; }}
  108. 108. Fera échouer la transactionpublic class CompteBancaire extends UntypedTransactor { private final Ref<Integer> balance = new Ref<Integer>(0) ; public void atomically(final Object message) { if (message instanceof Depot) { int montant = ((Depot)message).montant ; if (montant > 0) balance.swap(balance.get() + montant) ; } if (message instanceof Retrait) { int montant = ((Retrait)message).montant ; if (montant > 0) { if (balance.get() < montant) throw new IllegalStateException("...") ; balance.swap(balance.get() - montant) ; } } if (message instanceof GetBalance) getContext().replySafe((new Balance(balance.get()))) ; }}
  109. 109. public class Transfert { public final ActorRef source ; public final ActorRef destination ; public final int montant ; public Transfert(final ActorRef source, final ActorRef destination, final int montant) { this.source = source ; this.destination = destination ; this.montant = montant ; }}
  110. 110. Ensemble d’appels d’acteurspublic class ServiceBancaire extends UntypedTransactor { public Set<SendTo> coordinate(final Object message) { if (message instanceof Transfert) { Set<SendTo> s = new HashSet<SendTo>() ; Transfert t = (Transfert)message ; if (t.montant > 0) { // validation s.add(sendTo(t.destination, new Depot(t.montant))) ; s.add(sendTo(t.source, new Retrait(t.montant))) ; return Collections.unmodifiableSet(s) ; } } return nobody() ; }}
  111. 111. Ensemble d’appels d’acteurspublic class ServiceBancaire extends UntypedTransactor { public Set<SendTo> coordinate(final Object message) { if (message instanceof Transfert) { Set<SendTo> s = new HashSet<SendTo>() ; Transfert t = (Transfert)message ; if (t.montant > 0) { // validation s.add(sendTo(t.destination, new Depot(t.montant))) ; s.add(sendTo(t.source, new Retrait(t.montant))) ; return Collections.unmodifiableSet(s) ; } } return nobody() ; }}
  112. 112. Appel dans une transactionpublic class ServiceBancaire extends UntypedTransactor { public Set<SendTo> coordinate(final Object message) { if (message instanceof Transfert) { Set<SendTo> s = new HashSet<SendTo>() ; Transfert t = (Transfert)message ; if (t.montant > 0) { // validation s.add(sendTo(t.destination, new Depot(t.montant))) ; s.add(sendTo(t.source, new Retrait(t.montant))) ; return Collections.unmodifiableSet(s) ; } } return nobody() ; }}
  113. 113. Exécution transactionnelle• Chaque acteur gère un compte• Il possède un état, mais qui n’est jamais partagé• Les transferts sont gérés par un acteur sans état• Toutes les opérations sont transactionnelles
  114. 114. Bilan STM & acteurs• STM & acteurs : deux approches alternatives à synchronized• Offrent des fonctionnalités supplémentaires• Vont bénéficier du support de l’assembleur• Pas de miracle au niveau performance
  115. 115. Parallélisation des calculs
  116. 116. Nouveautés Java 7 & 8• Pattern Fork / Join• API non incluse en Java 7 : parallel arrays• Méthode en Java 8 : parallel()Objet :• Automatiser la parallélisation sur les tableaux et les collections• Ne plus avoir à écrire de code de parallélisation
  117. 117. Java 7 : fork / join
  118. 118. Fork / Join• Traite des calculs sur de grandes quantités de données, numériques ou non• Gère des tâches – Si elle est trop grosse elle se divise : Fork – Sinon elle s’exécute et retourne son résultat• Une tâche qui s’est divisée récupère les résultats de ses sous-tâches : Join
  119. 119. Fork / Join• Gère un pool de threads• Chaque thread possède une file d’attente qui stocke les tâches• Quand sa file d’attente est vide, il va voler du travail à son voisin
  120. 120. Fork / Join• Chaque tâche travaille sur ses propres données• Pas de bloc synchronisé• Pas de variables partagées• On doit donc « dupliquer » des informations• Cas du traitement des tableaux de grande taille ?
  121. 121. Parallel Arrays Java 6 &7
  122. 122. Parallel Arrays• API non incluse dans le JDK• Peut être utilisée en Java 6• Fork / Join dans un package jsr166y.*• Avantage : API auto-porteuse
  123. 123. Pourquoi les parallel arrays ne sont-ils pas dans l’API Java 7 ?
  124. 124. Java 8Sept. 2013
  125. 125. Syntaxe • Du light !int maxAge = persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = persons.filter(p -> p.age > 40).into(new ArrayList()) ;
  126. 126. Syntaxe Type Collection • Du light !int maxAge = persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = persons.filter(p -> p.age > 40).into(new ArrayList()) ;
  127. 127. Syntaxe D’où viennent les méthodes map() et filter() ?? • Du light !int maxAge = persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = persons.filter(p -> p.age > 40).into(new ArrayList()) ;
  128. 128. Syntaxe • Du light !int maxAge = persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = persons.filter(p -> p.age > 40).into(new ArrayList()) ; • Évolution de l’API Collection, méthodes vituelles d’extension
  129. 129. Méthodes virtuelles d’ext.• On ajoute des méthodes dans les interfaces, avec leurs implémentation par défaut public interface Collection<E> { public boolean add(E e) ; public boolean addAll(Collection<? extends E> c) ; // la litanie des méthodes de Collection // méthode virtuelle dextension public void sort(Comparator<? super E> comp) default Collections.sort(comp) ; }
  130. 130. Syntaxe • Du light !int maxAge = persons.map(p -> p.getAge()).reduce(0, Integer::max) ;Collection<Person> oldies = persons.filter(p -> p.age > 40).into(new ArrayList()) ; • Support du parallélismeCollection<Person> oldies = persons.parallel().filter(p -> p.age > 40) .into(new ArrayList()) ;
  131. 131. Interface spliterable()• Extension d’iterable()• Type de retour de parallel()• Le fork / join devient un framework système• Les fonctionnalités des parallel arrays sont intégrées via les lambdas• On gagne java.util.parallel
  132. 132. Algorithmique
  133. 133. Une anecdoteLe 24/2/2012 Heinz Kabutz lance un défi :• Déterminer les 10 premiers et 10 derniers octets du nombre Fibonacci (1 milliard)• Taille du nombre écrit dans un fichier = ~180Mo
  134. 134. Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs
  135. 135. Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs• 1ère amélioration : 3300s sur un CPU 4 cœurs
  136. 136. Une anecdote• Record à battre : 5600s sur un CPU 8 cœurs• 1ère amélioration : 3300s sur un CPU 4 cœurs• 2ème amélioration : 51s sur un cœur
  137. 137. Une anecdotePar quel miracle ?• Utilisation de GNU Multiple Precision Arithmetic Lib (GMP)• Changement d’implémentation de BigInteger• Changement d’algorithme de calcul de Fibonacci• Suppression de l’utilisation de la récursivité
  138. 138. Par quel miracle ? Quel rapport avec• Utilisation de GNU Multiple Precision Arithmetic Lib (GMP)• Changement d’implémentation de Fork / Join ou la BigInteger• Changement d’algorithme de calcul de parallélisation ? Fibonacci• Suppression de l’utilisation de la récursivité
  139. 139. AlgorithmiqueL’optimisation des fonctions linéaires a gagné un facteur 43M sur les temps de traitement en 15 ans :• 1k est dû à la vitesse des processeurs• 43k est dû à l’amélioration des algorithmes
  140. 140. Moralité• Utiliser les bons algorithmes de traitement avant de penser à la parallélisation
  141. 141. Moralité• Utiliser les bons algorithmes de traitement avant de penser à la parallélisation• S’assurer que les algorithmes sont bien parallélisables !!
  142. 142. Moralité• Utiliser les bons algorithmes de traitement avant de penser à la parallélisation• S’assurer que les algorithmes sont bien parallélisables !!Quick sort : se parallélise mal• Merge sort consomme de la mémoire
  143. 143. Moralité• Utiliser les bons algorithmes de traitement avant de penser à la parallélisation• S’assurer que les algorithmes sont bien parallélisables !!Recuit simulé : ne se parallélise pas, perd ses propriétés de convergence
  144. 144. Conclusion
  145. 145. ConclusionUne nouvelle période charnière se déroule en ce momentEn 1995 : la mémoire est devenue une ressource gérée par la JVMEn 2012 : le CPU est en train de devenir une ressource gérée par la JVM (et le serveur aussi !)Les langages et les processeurs s’adaptent les uns aux autres
  146. 146. ConclusionLes applications vont utiliser des traitements en parallèle de façon transparenteMais les pièges se trouvent au niveau des algorithmes, ils seront plus durs à éviterNouveaux challenges pour les développeurs, et de nouvelles opportunités !
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×