ProgrammationDéveloppeur Java middle/backend

Que savez-vous sur le travail avec les threads en Java et comment organiser la sécurité des threads ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

En Java, le travail avec les threads est réalisé à travers les classes Thread, Runnable et du paquet java.util.concurrent. Pour organiser la sécurité des threads, différents mécanismes de synchronisation sont utilisés :

  • Blocs/méthodes synchronisés (synchronized) permettent à plusieurs threads d'accéder à des données communes sans concurrence.
  • volatile garantit la visibilité des changements de variable entre les threads.
  • Classes de java.util.concurrent (par exemple, ReentrantLock, Semaphore, AtomicInteger, ConcurrentHashMap) offrent des moyens de synchronisation plus flexibles.

Exemple de synchronisation :

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

Exemple utilisant des classes atomiques :

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }

Question piégeuse.

Le mot-clé volatile garantit-il la sécurité des threads lors de l'incrémentation d'un compteur de type int ?

Réponse : Non. volatile assure seulement la visibilité de la valeur entre les threads, mais pas l'atomicité des opérations. L'incrémentation n'est pas une opération atomique (count++ consiste en lecture, augmentation et écriture), donc il peut y avoir des pertes de données. Pour un incrément sécurisé par les threads, une synchronisation ou des classes comme AtomicInteger sont nécessaires.

volatile int count = 0; // count++ n'est pas sécurisé par les threads !

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


Histoire

Dans un magasin en ligne, le compte de bonus était mis à jour via un compteur volatile. Sous la charge de milliers d'utilisateurs commandant des produits, une partie des bonus se perdait en raison de la concurrence des threads sur count++.


Histoire

Un employé a utilisé une liste ArrayList ordinaire comme tampon commun entre le producteur et le consommateur dans une application multi-thread, ce qui a conduit à des ConcurrentModificationException. La solution a été d'utiliser des blocs synchronisés ou de remplacer par CopyOnWriteArrayList.


Histoire

Dans le traitement des paiements, un développeur exécutait l'opération "vérifier et déduire le montant" via deux méthodes non liées. Dans des conditions de forte charge, cela entraînait des doubles débits jusqu'à l'implémentation de transactions atomiques et de verrous.