volatile garantit la visibilité et l'ordonnancement : une écriture est vue par tout thread qui lit ensuite ce champ, et elle établit une relation happens-before, donc les écritures faites avant sont visibles aussi. Il ne donne pas l'atomicité, donc un incrément de compteur reste une situation de compétition parce que c'est une lecture, une addition et une écriture. Pour des actions composées, utilisez synchronized, un verrou, ou une classe atomique comme AtomicLong.
Pourquoi les recruteurs posent cette question
C'est la façon la plus nette de savoir si quelqu'un comprend le modèle mémoire de Java ou sait seulement que volatile veut dire partagé. Le recruteur veut la distinction visibilité contre atomicité énoncée précisément, plus un cas d'usage valable comme un drapeau d'arrêt. Les relances vont souvent vers le double-checked locking, les classes atomiques et la façon dont synchronized fournit à la fois l'exclusion mutuelle et les mêmes effets mémoire.
Comment structurer votre réponse
- Découpez la garantie en visibilité et ordonnancement.
- Dites clairement ce qu'il ne fait pas : les opérations composées restent en compétition.
- Donnez un usage légitime, comme un drapeau qui arrête une boucle.
- Nommez ce que vous utilisez à la place quand il vous faut l'atomicité.
Exemple de réponse
volatile veut dire qu'une lecture voit toujours l'écriture la plus récente plutôt qu'une valeur en cache dans un registre ou dans le cache d'un cœur, et cela empêche le compilateur et le processeur de réordonner autour. Dans les termes du modèle mémoire, cela crée une relation happens-before, donc tout ce que le thread écrivain a fait avant l'écriture volatile est visible par un thread qui la lit ensuite. Ce que ça ne me donne pas, c'est l'atomicité. Un incrément de compteur, ce sont trois opérations, donc deux threads peuvent lire la même valeur et une mise à jour est perdue, peu importe que le champ soit volatile. Mon usage valable habituel, c'est un booléen qui dit à une boucle de fond de s'arrêter, où une seule écriture et une seule lecture correspondent exactement au motif. Tout ce qui est lecture-modification-écriture passe à un AtomicInteger, à un LongAdder si c'est assez sollicité pour que la contention compte, ou à un verrou si plusieurs champs doivent changer ensemble. L'autre endroit où je m'appuie sur le modèle mémoire, c'est la publication sûre, puisque les champs final sont garantis visibles après construction, ce qui est une bonne raison de rendre les choses immuables.
Vous passez cet entretien bientôt ? GhostPilot écoute votre appel en direct, repère la question dès qu'elle est posée et affiche une réponse structurée à l'écran en temps réel. Essayez-le lors de votre prochain entretien blanc, ou prenez un Session Pass à $29, sans abonnement, pour le jour J.
Voir comment ça marcheQuestions de relance à prévoir
- Pourquoi le double-checked locking était-il cassé avant que volatile ne soit corrigé ?
- Comment synchronized vous donne-t-il les mêmes garanties mémoire ?
- Quand utiliseriez-vous LongAdder plutôt qu'AtomicLong ?
Autres questions pour Développeur Java
Votre recruteur posera sa propre version de celle-ci. Collez votre véritable fiche de poste dans le Question Predictor gratuit et obtenez les 20 questions que ce poste a le plus de chances de poser, avec ce que chacune cherche vraiment à sonder.
Prédire mes questions