46
Programmation concurrente en Java Florian Beaufumé 03/2017

Programmation concurrente en Java

Embed Size (px)

Citation preview

Programmation concurrente en Java

Florian Beaufumé

03/2017

Florian Beaufumé

• Architecte logiciel Java et web

• Freelance

[email protected]

• www.adeliosys.fr

• www.linkedin.com/in/fbeaufume

• fr.slideshare.net/fbeaufume

• Concepts

• Java SE

• Java EE et Spring

Sommaire

Concepts

• "Le nombre de transistor double tous les deux ans"

• "La fréquence double chaque 1,5 année"

Lois de Moore

• Concurrence :

• Des tâches qui peuvent se chevaucher

• Alternées ou pas

• Parallélisme :

• Exécution simultanées au niveau matériel

Concurrence vs parallélisme

• Gain maximal de latence suivant la part parallélisable du

traitement

Loi d'Amdahl

• Processus découpé en threads

• Natif vs green

• Ordonnancement préemptif vs coopératif

• Time slicing

• Fonctionnalités de distribution et coordination

• Bénéfices

• Utilisation des ressources

• Réactivité

• Couts

• Complexité de conception et débugging

• Ressources par thread et context switching

Modèle multi-threads

• Thread safe < Immutable < Stateless

• Section critique

• Opération atomique

• Contention

• Deadlock

• Starvation

Définitions

Java SE

• Concurrence intégrée au langage

• Basé sur des threads :

• Nom

• Priorité : 1 à 10

• Daemon ou pas

• Etat : NEW, RUNNABLE, BLOCKED, WAITING, etc.

• Pile d'appel

• Exemple :

• Mémoire partagée suivant le Java Memory Model

Java 1.0

Java 1.0 - Threads de base

• Synchronisation de threads pour accéder à des données

Java 1.0 - Synchronized

• Permet d'implémenter un scope request :

• Sécurité (identité, droits)

• Transaction

• Tenant

• Java 1.2 : InheritableThreadLocal

Java 1.0 - ThreadLocal

• Exemple java.util.Timer :

• Un thread par timer

• Pas de garantie d'exécution

Java 1.3 - Timers

• Ajout de java.util.concurrent, merci Doug Lea

• Java Memory Model

• Interactions entre les threads

et la mémoire

• "Happens before"

• Volatile :

• R et W en mémoire principale

plutôt que sur cache CPU

• Rend R et W 64 bits (long et

double) atomique

• Mais pas un incrément

• Permet de la synchronisation

simple

Java 5

• Volatile seul

• Synchronized en écriture + volatile

Java 5 - Volatile

• Singleton lazy loadé classique

• Via double checked locking

Java 5 - Double checked locking

• ReentrantLock

• ReentrantReadWriteLock

Java 5 - Locks

• Coordination de threads sur des étapes

Java 5 - CountDownLatch

main

workers

await()

countdown()

• Map<K, V>

• Hashtable : synchronisée, clés et valeurs non null

• HashMap : pas synchronisée, accepte clés et valeurs nulles

• ConcurrentMap<K, V>

• Etend Map<K, V>

• Méthodes atomiques comme putIfAbsent(key, value)

• ConcurrentHashMap, implémentation efficace

Java 5 - ConcurrentHashMap

• Exécution de tâches sur pool de threads

Java 5 - Executors (1/2)

Executor

Executor

Service

ThreadPool

Executor

Interfaces Classes

Scheduled

Executor

Service

Scheduled

ThreadPool

Executor

void execute(Runnable)

Supporte Future, ex :

Future<T> submit(Callable<T> task)

Supporte scheduling, ex :

ScheduledFuture scheduleAtFixedRate(

Runnable command,

long initialDelay,

long period,

TimeUnit unit)

Java 5 - Executors (2/2)

• Nombres atomiques

• Semaphore

• Et d'autres

Java 5 - Divers

• Equivalent mono-JVM de MapReduce

• Décompose une tache en sous-taches et recompose le

résultat final

• Fonctionne par work-stealing

• Etendre RecursiveAction (si pas de résultat) ou

RecursiveTask (si résultat)

Java 7 - Fork/join (1/2)

Java 7 - Fork/join (2/2)

• Adder

• Bonnes performances (reporte les ajouts si besoin)

• Accumulator

• Généralisation de l'Adder

Java 8 - Adders et accumulators

Java 8 - StampedLock (1/2)

synchronized

synchronized (W)

et volatile

ReentrantLock

ReentrantRWLock

StampedLock

Simplicité

Bonnes perfs en lecture

Ajout de fonctionnalités (timed

wait, try lock, etc.)

Bonnes perfs en lecture

Bonnes perfs, fonctionnalités

(upgrade de lock R en W, etc.)

Fonctionnalités

Java 8 - StampedLock (2/2)

• Execution dans le ForkJoinPool commun

• Parallélisme du ForkJoinPool commun :

• Par system property :

• -Djava.util.concurrent.ForkJoinPool.common.parallelism=7

• Sinon Runtime.getRuntime().availableProcessors() - 1

• Le thread courant aussi est utilisé

• Ou dans un ForkJoinPool custom

Java 8 - Parallel streams (1/2)

• Pas toujours plus performant, varie suivant :

• Type de collection : ArrayList plutôt que LinkedList

• Nature du traitement

• Taille de "N*Q" (nb d'élément * cout par élément)

• Nombre de cœurs, il faut > 1

• Mesurer les deux

• Par défaut utilisent tous le ForkJoinPool commun

• Attention aux lambdas stateful

Java 8 - Parallel streams (2/2)

• Classe qui implémente Future et CompletionStage

• Pour combiner/chainer des actions

• Syntaxe fonctionnelle

Java 8 - CompletableFuture

Java EE et Spring

• Modèle "thread-per-request" avec pools de thread

(HTTP/Servlet, EJB)

• Solutions Java SE fonctionnent mais…

• … utiliser les threads du framework

• Contextes de sécurité et de transaction

• Modèles de composants (Servlet, EJB, Spring, etc) :

• Cycle de vie et scope : request, session, etc.

• Modèle de concurrence, voir de locking

Principes généraux

• Servlet

• SingleThreadModel est déprécié

• Une instance pour toutes les requêtes, donc thread-safe

• Spring et CDI

• Concurrence manuelle via solutions de Java SE

• EJB session singleton

• @ConcurrencyManagement : container ou bean

• @AccessTimeout

• @Lock : read ou write

• Autres

Concurrence des composants

• EJB 3.1 (Java EE 6)

• Spring 3 ou Spring Data

• CDI

• Peut s'implémenter via intercepteur maison

• Evènements asynchrones de CDI 2 (Java EE 8)

Méthodes asynchrones

• Concurrency Utilities (Java EE 7)

• Spring

Executors

• EJB 3.1 Timer Service (Java EE 6)

• Concurrency Utilities (Java EE 7)

• Spring 3

Scheduling

• Concurrence d'accès aux données entre requêtes

utilisateurs

• "Transaction longue" quand plusieurs transactions de BD

• Solutions : locking optimiste ou pessimiste

Locking de persistance

R1 W1

R2 W2

t Conflit

• Fonctionnement

• OptimisticLockException en cas de problème

• Pour faible taux de conflits

• Bénéfices

• Scalabilité

• Portabilité

• Inconvénients

• Gérer le conflit : reload, force, merge

Locking optimiste

R W

t

version=3 version=4 JPA

Hibernate "update … where version=3" "select …"

• Fonctionnement

• Pour fort taux de conflits

• Bénéfices

• Simplicité

• Inconvénients

• Contention

• Pour transactions courtes

Locking pessimiste par la base

R W

t

"select … for update" "update …"

JPA 2

Hibernate

• Fonctionnement

• Table de lock (id, entityClass, entityId, userId, date)

• Pour fort taux de conflits

• Bénéfices

• Fonctions avancées (monitoring, historisation, etc)

• Inconvénients

• Mode édition dans l'UI

• Gérer l'expiration des locks

• Plus d'accès à la base

• Contention

Locking pessimiste applicatif

R W

t

JPA

Hibernate

Lock Unlock