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

MICI au travail : Le handicap invisible qui révèle des forces insoupçonnées

Les maladies inflammatoires chroniques de l’intestin ou "MICI" sont invisibles, mais leurs impacts sur la…

3 jours ago

Exploiter les NPUs pour de l’IA embarquée dans les applis webs

Depuis l'été, j'ai un Pixel qui intègre à la fois un TPU (Tensor Processing Unit)…

6 jours ago

Qcm saison hiver 2024 : toutes les infos.

On se retrouve dans un nouvel article avec toutes les infos sur cette nouvelle saison…

3 semaines ago

L’inclusion numérique est essentielle.

Pourquoi l’inclusion numérique est essentielle : le point avec Mathieu Froidure. Dans un monde de…

4 semaines ago

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…

1 mois ago