Credit photo mstcweb licence Commons CreativeLors d’un entretien d’évaluation en mai dernier pour le compte d’une grande banque, la personne en face de moi me demande la différence entre volatile et synchronized. J’avoue que je n’ai pas répondu tout à fait correctement. Voici donc quelques éléments de réponses, il est toujours bon d’apprendre quelque chose.

Avant tout vous ne serez amené à utilisez synchronized et volatile qu’à de rares occasions si vous travaillez sur une bonne vieille application de gestion. Vu la qualité de certaines API comme Google Guava, mon premier conseil est le suivant : soyez humble. Allez voir un peu sur Internet les dernières nouveautés de ces API plutôt que de vous lancer dans du développement d’application parallèle.

Depuis Java 5 la définition formelle du mot clé volatile a un peu changé. Dans cet article de Brian Goetz de 2004 sur la JSR-133, Brian présente la différence d’approche sur le modèle mémoire de la JVM. Cela me rappelle un article sur le pattern Double-checked locking dont j’ai parlé il y a 5 ans sur le Touilleur Express. En quelques mots, le mot clé volatile permet de signifier à la JVM qu’une variable sera modifiée par plusieurs Threads. En déclarant une variable volatile, sa valeur ne sera jamais placée dans le cache local à la Thread courante d’exécution. Chaque lecture et chaque écriture passeront forcément par la mémoire partagée entre les Threads. De fait, l’accès à la variable elle-même devient implicitement synchronisé. Et ce, bien plus efficacement qu’avec un marqueur synchronized sur des méthodes.

C’est de la synchronisation implicite, tout du moins vu de l’oeil du programmeur. Les subtilités de la JVM et le modèle mémoire sont un peu plus complexe que cela. Si nous voulions comparer ces 2 opérateurs, nous pourrions dire que synchronized s’applique uniquement à des Objets alors que volatile peut s’utiliser aussi sur des types primitifs.

Le tableau suivant tiré de cet article résume les différences entre synchronized et volatile :

Characteristic Synchronized Volatile
Type of variable Object Object or primitive
Null allowed? No Yes
Can block? Yes No
All cached variables synchronized on access? Yes From Java 5 onwards
When synchronization happens When you explicitly enter/exit a synchronized block Whenever a volatile variable is accessed.
Can be used to combined several operations into an atomic operation? Yes Pre-Java 5, no. Atomic get-set of volatiles possible in Java 5.
Difference between synchronized and volatile

Le mot clé volatile ne rend pas l’accès bloquant pour une Thread, comme le fait synchronized. Ce n’est donc pas une solution pour faire un sémaphore, une barrière, bref des patterns d’inter-lockages de Threads. Un accès à une variable volatile ne peut pas bloquer une Thread. Alors que synchronized s’applique à un objet, volatile s’applique à la référence d’un objet… qui peut être null. C’est bien l’accès à la référence qui est garantis.

Au quotidien vous ne verrez que très rarement finalement le mot clé volatile. Ce que l’on voit dans les APis par contre, c’est des types comme AtomicInteger ou sinon des décorateurs complexes comme AtomicReference.

Par expérience donc, je vous recommande plutôt de faire confiance à des APIs publiques et open-source plutôt que de vous lancer dans l’utilisation de ces types complexes. Si vous travaillez sur une API, allez-y. Mais si vous travaillez sur un projet que quelqu’un doit pouvoir maintenir facilement, évitez de vous lancer dans l’implémentation de tout ce qui tourne autour de la synchronisation.

Et donc au prochain entretien que j’aurai, si je ne sais pas répondre je pourrai au moins dire : « et vous avez vu sinon l’article sur le blog le Touilleur Express ? Et bien c’est moi qui l’ai écrit »

Références
http://www.javamex.com/tutorials/synchronization_volatile.shtml
http://www.flickr.com/photos/mstcweb/3550301596/sizes/m/in/photostream/ Photo trouvée sur FlickR, libre de droits en licence Commons Creatives, prise par mstcweb.

3 réflexions sur « Quelle est la différence entre volatile et synchronized ? »

  1. Certaines subtilités sont aussi à noter pour éviter certains pieges pas facile à débusquer, comme la non atomicité d’opérations comme les increments/decrements presque anodins que sont ++ et –. Une variable volatile ne garantira en aucun cas l’atomicité d’une telle opération sur elle, et cela conduira à des comportements difficle à cerner. Un synchronized lui le pourra, ou l’usage de l’API concurrent(.atomic)

    On ne peut pas toujours éviter d’avoir à traiter des cas d’accès concurrents, et ce même sans développer des API. Je ne pense pas donc qu’il faille en décourager l’écriture, mais plutôt en encourager l’apprentissage. Ainsi ces notions seront utilisées aux bons endroits de la bonne façon.

    My 2 cts 😉

  2. Completement d’accord avec David… lorsqu’on a à développer une appli avec du multithreading, je vois mal comment on peut s’en sortir si de base on n’a pas saisit et compris ces deux mots clés… (c’est pas évident, j’avoue que je m’y perds).

Les commentaires sont fermés.