De la nécessité d’utiliser des structures de données thread-safe en environnement multithread

Parfois, en environnement multithread, il peut être tentant d’utiliser des structures de données qui ne sont pas thread-safe. Je pense notamment aux Map utilisées comme cache, pour lesquelles on pourrait être tenté de se dire :

1. Ce n’est pas grave si la donnée est écrite par plusieurs threads différents dans la Map, étant donné que le couple clef/valeur sera le même.

2. La synchronisation coûte cher, donc autant éviter de l’utiliser. Le problème de cette approche est qu’en fait, les structures de données thread-safe ne le sont pas pour vos données, et ne le sont pas non plus au niveau de leur état interne.

Cela signifie tout simplement que leur état interne peut se corrompre et donner des effets de bord assez… indésirables.

Par exemple, si vous utilisez une HashMap en multithread, vous risquez d’obtenir des boucles infinies, tel que détaillé dans ce rapport de bug. A titre personnel, j’ai déjà fait monter le load average d’un serveur quad core à 42 pour une HashMap utilisée dans un filtre http en lieu et place de son équivalent thread-safe.

Alors bien évidemment on peut se dire qu’il suffit de mettre un bloc synchronized autour de chaque appel aux structures concernées, mais chacun de ces blocs implique une barrière en lecture/écriture qui est extrêmement coûteuse. Les dernières versions de la JVM savent heureusement ignorer les blocs synchronized quand l’objet n’est pas utilisé en contexte multithread. Mais quand même !

Pour éviter de telles mésaventures, voici une liste non exhaustive de structures de données à utiliser sur des objets dont les instances peuvent être partagées entre plusieurs threads :

Structure non thread-safe Equivalent thread-safe Commentaires
java.util.HashMap et java.util.HashSet java.util.concurrent.ConcurrentHashMap java.util.Hashtable Ces structures n’acceptent ni clef, ni valeur nulle. La ConcurrentHashMap est nettement plus rapide que la Hashtable. Le HashSet utilise en fait une HashMap de manière sous-jacente, l’astuce consiste donc à utiliser les Map thread-safe avec la valeur égale à la clef.
java.util.TreeMap et java.util.TreeSet java.util.concurrent.ConcurrentSkipListMap Le TreeSet utilise en fait une TreeMap de manière sous-jacente. L’astuce consiste donc à utiliser les Map thread-safe avec la valeur égale à la clef.
java.util.ArrayList et java.util.LinkedList java.util.Vector Alors oui Vector date, mais il est thread-safe contrairement à ArrayList. Cela évitera les mauvaises surprises lors du redimensionnement du tableau sous-jacent à la liste.

Cet article vous a plu ? Vous aimerez sûrement aussi :

Julien
Moi c’est Julien, ingénieur en informatique avec quelques années d’expérience. Je suis tombé dans la marmite étant petit, mon père avait acheté un Apple – avant même ma naissance (oui ça date !). Et maintenant je me passionne essentiellement pour tout ce qui est du monde Java et du système, les OS open source en particulier.

Au quotidien, je suis devops, bref je fais du dév, je discute avec les opérationnels, et je fais du conseil auprès des clients.

Son Twitter Son LinkedIn

gojul

Recent Posts

Communauté Tech et féminine : Interview avec Helvira de Motiv’her

Elles sont passées où les femmes dans la tech ? Entre le manque de représentation…

3 jours ago

Consommer des APIs HTTP en PHP comme un pro avec Nicolas Grekas.

Dans cette vidéo, on interview Nicolas Grekas, contributeur clé de Symfony, pour discuter de sa…

3 jours ago

Trouver son job grâce à WeLoveDevs.

 Comment trouver son job dans la tech ? Marie a la réponse ! Grâce à…

5 jours ago

Adobe, L’empire créatif.

Adobe, l'empire créatif, et pas des moindres ! Belle ascension de la part de ces…

1 semaine ago

La MAO musique ou musique assistée par ordinateur

Est-ce plus simple de créer des morceaux avec les outils de Musique Assistée par Ordinateur…

1 semaine ago