Valeur du getter impossible à tester

FlorianGaudon - Modifié le 26 janv. 2019 à 06:57
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 - 26 janv. 2019 à 15:04
Bonsoir à tous,

J'ai un petit problème dans le code suivant :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class Ex {
  int attribut ;
  Timer chrono;
  private ActionListener refreshChrono ;
  
  public Ex(){
   attribut = 0;
   chrono = new Timer(1000,refreshChrono);
   refreshChrono = new ActionListener() {
   public void actionPerformed(ActionEvent e1)
    { 
      attribut = 1;
    }
    };
     
     chrono = new Timer(1000,refreshChrono);
     chrono.start();
     
    }
  
  public static void main(String[] args){
   
   Ex exmple = new Ex();
   System.out.println(exmple.get());
   
   while(true){
     System.out.println(exmple.get());
     
     if(exmple.get() == 1) {
      System.out.println("CoucouMain");
     }
    }
 }

  int get() {
   return attribut;
  }
}


En effet quand dans le while du main, je print exmple.get() je rentre dans le if alors que si je commente le print je n'y rentre plus..
Si quelqu'un sait m"expliquer pourquoi je suis preneur !
Merci d'avance :)

1 réponse

KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 127
26 janv. 2019 à 10:38
Bonjour,

C'est une question très intéressante, il m'a fallu quelques minutes avant de trouver la solution, c'est le genre de piège où je pourrais encore me faire avoir.

Déjà on peut simplifier ton code et j'en profite pour te montrer une alternative afin d'éviter d'utiliser du code Swing alors que tu n'as pas d'interface graphique (mais le bug reste le même).

import java.util.concurrent.*;
// import javax.swing.Timer;

public class Ex {
    private int attribut;

    public Ex() {
        // new Timer(1000, e -> attribut = 1).start();
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> attribut = 1, 1L, 1L, TimeUnit.SECONDS);
    }

    public static void main(String[] args) {
        Ex ex = new Ex();
        while (true) {
            // System.out.println(ex.attribut);
            if (ex.attribut == 1) {
                System.out.println("CoucouMain");
            }
        }
    }
}

Pour corriger le bug, il faut rajouter le mot clé volatile à ton attribut :
private volatile int attribut;

Tu trouveras beaucoup d'explication sur ce mot clé, par exemple ici, ce qu'il se cache derrière c'est une optimisation de la JVM qui met en cache la valeur de l'attribut, mais il faut la forcer à se mettre à jour.
2
FlorianGaudon Messages postés 1 Date d'inscription vendredi 25 janvier 2019 Statut Membre Dernière intervention 26 janvier 2019
26 janv. 2019 à 11:48
Bonjour ! :)
Merci beaucoup pour la réponse précise et rapide ! J'ai simplifié mon code de base volontairement pour que la recherche du bug soit plus simple mais de base j'utilise une interface graphique.
Mais du coup je doit rajouter volatile à tous mes attributs qui peuvent être accéder par la déclaration d'un objet ?
A chaque fois que je vais vouloir faire ex.attribut il faudra que l'attribut concerné soit déclaré en volatile ?!

Merci encore de ta réponse rapide et efficace ! :D
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 127 > FlorianGaudon Messages postés 1 Date d'inscription vendredi 25 janvier 2019 Statut Membre Dernière intervention 26 janvier 2019
26 janv. 2019 à 15:04
C'est un problème qui ne se pose que parce que tu as un thread d'écriture différent des threads de lecture, si ton objet était construit, modifié et lu par le même thread (ce qui est souvent le cas) il n'y aurait pas de conflit.

volatile
va forcer la JVM à relire la valeur de l'objet entier, donc même s'il n'y a qu'un seul attribut volatile, ils seront tous mis à jour. Mais pour la clarté du code, il vaut mieux ajouter le mot clé volatile à chaque attribut qui serait encore concerné si on supprimait tous les autres attributs.

Voir l'article de Brian Goetz (architecte du langage Java) : Java theory and practice : Managing volatility
0
Rejoignez-nous