ProgrammationDéveloppeur Backend

Comment fonctionne le mécanisme synchronized en Java ? Quand l'appliquer et quels sont les pièges à éviter lors de la synchronisation d'accès aux ressources ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

Depuis l'apparition de Java, les développeurs ont été confrontés au problème d'accès concurrentiel aux ressources communes. Pour résoudre ce problème, des primitives de synchronisation de haut niveau ont été introduites, dont le modificateur clé synchronized.

Problème :

Sans synchronisation, dans les applications multithread, les ressources partagées peuvent être corrompues : des data races peuvent apparaître, et l'état de l'objet devient imprévisible.

Solution :

synchronized permet d'organiser un moniteur pour une méthode ou un bloc de code, garantissant l'accès à une seule thread à la fois dans la section critique. La synchronisation d'une thread peut être mise en œuvre au niveau de la méthode ou du bloc.

Exemple de verrouillage d'objet :

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

Les blocs peuvent également être synchronisés :

public void safeIncrement() { synchronized(this) { count++; } }

Caractéristiques clés :

  • La synchronisation au niveau de la méthode est équivalente à la synchronisation au niveau de this.
  • Pour les méthodes statiques, la synchronisation se fait par l'objet de classe.
  • Il est nécessaire de minimiser la portée de la section critique.

Questions pièges.

Quelle est la différence entre une méthode synchronized et un bloc synchronized ?

La méthode synchronized bloque toute la méthode pour l'objet courant (this) ou la classe (si la méthode est static). Le bloc permet de synchroniser uniquement le morceau de code nécessaire et de choisir n'importe quel objet pour le verrouillage.

Deux threads différents peuvent-ils entrer simultanément dans deux méthodes synchronized différentes d'un même objet ?

Non, si les méthodes sont synchronisées sur le même moniteur (this). Si différents moniteurs sont utilisés, alors oui.

Le modificateur synchronized influence-t-il la visibilité des variables entre les threads ?

Oui, l'entrée dans le bloc synchronized réinitialise les caches des threads et met à jour les valeurs des variables (relation happens-before).

Erreurs typiques et anti-patterns

  • Synchronisation sur un objet "trop large" (par exemple, sur String ou un objet de classe)
  • Exécution prolongée de code à l'intérieur d'un bloc synchronisé
  • Mélange d'accès à une ressource via des blocs synchronized et des sections non synchronisées

Exemple de la vie réelle

Cas négatif

Un développeur synchronise des méthodes statiques d'une classe sur un objet d'instance, ce qui ne garantit pas l'exactitude lors de l'utilisation à travers différentes instances.

Avantages :

  • Mise en œuvre simple

Inconvénients :

  • Courses de données inattendues entre les threads
  • Bugs difficiles à détecter

Cas positif

Toutes les méthodes utilisant une ressource partagée sont synchronisées sur un même objet-moniteur, la portée de la section critique est minimale.

Avantages :

  • Les threads travaillent avec des données cohérentes
  • Blocage minimal

Inconvénients :

  • Plus difficile à maintenir et à analyser les blocages mutuels (deadlock), surtout avec un grand nombre d'objets synchronisés