IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Problème de concurrence dans Java


Sujet :

Java

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2010
    Messages : 18
    Par défaut Problème de concurrence dans Java
    Bonjour à tous,

    j'aurais une question qui m'embrouille sur un exemple que j'ai trouvé sur un livre sur la programmation concurrente en java dans le quel on donne un exemple d'une classe qui est modifiable alors que moi je pense qu'elle ne l'est pas.

    la classe en question est la suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public class Holder { 
      private int n; 
      public Holder(int n) { this.n = n; } 
      public void assertSanity() { 
        if (n != n) 
          throw new AssertionError("This statement is false."); 
      } 
    }
    et qui sera appelée par des threads dans un bout de programme comme le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public Holder holder; 
    public void initialize() { 
      holder = new Holder(42); 
    }
    Donc, qd je regarde l'exemple je suis un peu confus, car une classe immutable est une classe dans la quelle chaque référence d'objet de cette classe ne peux pas changer la valeurs de ces champs une fois construits.

    Pour moi, la classe Holder est immutable par costruction, même si le int n de l'objet holder n'est pas final !!!

    Est ce que quelqu'un aurait une explication et pourrais me dire dans quelle cas un objet holder pourrait changer de valeur (d'état) sans changer de référence ?

    Merci d'avance pour votre aide.

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par chimomura Voir le message
    Pour moi, la classe Holder est immutable par costruction, même si le int n de l'objet holder n'est pas final !!!

    Est ce que quelqu'un aurait une explication et pourrais me dire dans quelle cas un objet holder pourrait changer de valeur (d'état) sans changer de référence ?
    Moi non plus ça ne me semble pas possible en conditions normales.
    Ça doit pouvoir arriver avec du JNI, mais bon... Quand on en arrive là, on a d'autres soucis qu'assurer les accès concurrents .

    Je suppose qu'on est censé rendre la classe Holder mutable, à l'aide d'un setter.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2010
    Messages : 18
    Par défaut
    Bonjour thelvin,

    C'est ce que je pense moi aussi.

    Donc, je peux très bien avoir une classe immutable avec des champs (contentons nous des champs primitifs) qui soient non final mais juste private qui sont initialisés dans le constructeur et sans aucun setter sur ces champs ?

    Merci.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par chimomura Voir le message
    Donc, je peux très bien avoir une classe immutable avec des champs (contentons nous des champs primitifs) qui soient non final mais juste private qui sont initialisés dans le constructeur et sans aucun setter sur ces champs ?
    Disons que je ne trouve pas ça très propre. Quand on fait une classe immutable, on déclare ses champs final, point.

    Mais sauf erreur de ma part, oui, on peut faire des classes immutables sans les champs soient vraiment final.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    A noter que pour être réellement immuable, il faut également que la classe elle-même soit déclarée final afin de ne pas pouvoir être redéfinie. Sinon l'immuabilité ne peut pas être redéfinie.


    Concernant les champs ce n'est pas forcément une obligation, mais c'est nettement plus simple car cela rend le tout obligatoirement thread-safe...


    @chimomura : concernant l'exemple je pense qu'ils veulent montrer que la condition (n != n) peut être vrai dans certains cas lorsque l'attribut n'est pas final... Mais il faudrait voir l'exemple complet.

    a++

  6. #6
    Membre averti
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2010
    Messages : 18
    Par défaut
    Pour vous donner le contexte complet de l'exemple,

    en fait,

    on dispose d'une classe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public class Holder { 
      private int n; 
      public Holder(int n) { this.n = n; } 
      public void assertSanity() { 
        if (n != n) 
          throw new AssertionError("This statement is false."); 
      } 
    }

    cette classe est utilisé dans le bout de programme suivante, où elle est accédé par plusieurs thread

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public Holder holder; 
    public void initialize() { 
      holder = new Holder(42); 
    }
    dans le livre est dit :
    " Vous pourriez être surpris des conséquences de cet exemple qui semble pourtant anodin.
    À cause des problèmes de visibilité, l’objet Holder pourrait apparaître à un autre thread sous un état incohérent, bien que ses invariants aient été correctement établis par son constructeur ! Cette publication incorrecte pourrait permettre à un autre thread d’observer
    un objet partiellement construit "

    Moi, je suis d'accord sur le fait que d'autre threads pourraient voir l'objet holder en état partiellement construit alors qu'il est entrain d'être construit par un autre thread en même temps. toutefois, le problème ici est non pas la classe Holder elle-même, mais le fait que l’objet Holder ne soit pas
    correctement publié.

    autrement dit, si je mets

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static Holder holder = new Holder(42);
    ou lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public Holder holder; 
    public void initialize() { 
      holder = new Holder(42); 
    }
    je garantis que les threads ne verront plus d'objet partiellement construit.
    sans pour autant modifier la classe Holder

    Cependant, on pourrait immuniser Holder contre une publication incorrecte en
    déclarant le champ n final, ce qui rendrait Holder non modifiable

    jusqu'au là j'ai compris.

    Par contre, c'est dit après toujours dans le livre pour cet exemple :

    " Cependant, on pourrait immuniser Holder contre une publication incorrecte en déclarant le champ n final, ce qui rendrait Holder non modifiable"

    et

    " Les objets non modifiables ayant tant d’importance, le modèle mémoire de Java garantit une initialisation sûre pour les partager "

    et

    " Pour que cette garantie d’initialisation sûre puisse s’appliquer, il faut que toutes les exigences portant sur les objets non modifiables soient vérifiées : 1) état non modifiable ,
    2) tous les champs déclarés comme final
    3) construction correcte "

    Et là ou je comprends pas pourquoi l'objet holder tel qu'il est déclaré pourquoi il est mutable ?

    Merci pour votre aide.

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Ah, je vois.

    Mais la question n'est pas de savoir si la classe Holder est vraiment mutable en principe. La question est de savoir ce que la JVM va en penser.
    Avec un attribut final elle ne peut pas se tromper et, bien que j'admets que je n'en sais rien moi-même, l'auteur dit que dans ce cas, la JVM emploiera un modèle mémoire qui garantit que l'objet sera entièrement initialisé avant d'être visible par d'autres threads.

    Ça se tient. Je ne suis pas vraiment au courant moi-même, mais l'argument se tient.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    j'ai pas souvenance de telles notes (garanties) dans le JVM. Le meilleurs moyen reste de ne pas publier Holder tant qu'on a pas fini son initialisation.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public Holder holder; 
    public void initialize() { 
      Holder holder = new Holder(42); 
      this.holder = holder;
    }
    Le cas est rare et se produit quand la variable (holder) est stockée par la jvm dans le champ avant l'appel au constructeur, plutot que d'être stocké dans les registres.

  9. #9
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Avec la description c'est mieux : le problème vient de la méthode initialize() et du holder qui n'est pas protégé !

    Si la méthode initialize() est appelé pendant qu'un autre thread accède au holder il peut y avoir un problème lors de la création de l'instance.

    En effet la variable holder peut être initialiser à une valeur non-null avant la fin du constructeur, et donc avant que son attribut n soit initialisé...

    Lorsqu'un thread modifie une variable, il est possible que les autres threads ne voient qu'une partie de ces modifications, et pas forcément dans le bon ordre.

    Donc pour un autre thread, holder pourrait être initialiser, mais pas son attribut "n" qui serait toujours à zéro (valeur par défaut).
    C'est un peu le même problème que le double-check lockin du Singleton...




    C'est un cas assez dur à reproduire, mais le bug qu'il engendre peut être très pénible à trouver et donc à corriger.





    Lorsqu'on partage une variable entre plusieurs threads, il faut soit la synchroniser soit s'assurer qu'elle ne peut pas être modifié...


    a++


    [edit] Grillé par tchize_, mais je ne suis pas sûr que la variable temporaire ne soit pas supprimé par le compilateur après optimisation...

  10. #10
    Membre averti
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2010
    Messages : 18
    Par défaut
    donc si je résume en combinant vos deux derniers réponses:

    Le fait de déclarer de déclarer le int n dans la classe Holder final va obliger la JVM par la suite de placer l'objet holder dans le registre (et donc uniquement accessible par le thread qui le manipule ) et ne le passer dans la variable partagé holder que lorsque l'initialisation se termine.

    Toutefois, l'objet reste pas publié de façon sure car dans le livre est dit :
    " Les mécanismes de publication sûre garantissent tous que l’état publié d’un
    objet sera visible à tous les threads qui y accèdent dès que sa référence est visible"

    et dans le déclaration donné par tchize

    public Holder holder;
    public void initialize() {
    Holder holder = new Holder(42);
    this.holder = holder;
    }

    Un moment donné, on a bien la référence holder est visible avant même qu'elle soit initialisé par un thread donné, non ?

    Qu'est ce que vous en pensez ?

    Merci.

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Dans mon code, la référence reste privée dans initialize. On a bien appel au constructeur à la ligne qui précède le stockage, donc pas de soucis.

    Et ce n'est pas l'état du int qui pose problème, c'est bien le fait que ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public void initialize() {
    holder = new Holder(42);
    }
    Peut être exécuté de deux manières par la JVM (en pseudo code, je connais pas l'assembleur java ):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    registre1 = create object (Holder.class)
    invoke constructor (registre1,42)
    move (holder, registre1)
    return;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    holder = create object (Holder.class)
    invoke constructor (holder,42)
    return;
    Dans le deuxième cas, on vois le stockage de la nouvelle instance avant l'appel au constructeur.

  12. #12
    Membre averti
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2010
    Messages : 18
    Par défaut
    Je comprends mieux la problématique. je peux dire que le problème est résolu

    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème d'accent dans le script java
    Par anaice dans le forum Pentaho
    Réponses: 1
    Dernier message: 06/11/2009, 15h12
  2. Réponses: 2
    Dernier message: 09/04/2009, 07h52
  3. Problème de font dans un fichier excel généré en java
    Par jmmaugis dans le forum Documents
    Réponses: 0
    Dernier message: 09/09/2008, 09h26
  4. Problème de concurrence dans mon updateCommand
    Par Freygolo dans le forum VB.NET
    Réponses: 7
    Dernier message: 07/06/2007, 08h32
  5. Probléme d'ecriture dans un fichier texte en java
    Par oldscrout dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 19/01/2007, 19h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo