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

Langage Java Discussion :

Singleton multithread ThreadLocal ?


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 25
    Par défaut Singleton multithread ThreadLocal ?
    Bonjour,

    J'ai lu cette FAQ et je me suis demander si qu'elle était le probleme de cette implémentation qui n'y est pas présente:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public class Tmp {
    	static private Tmp instance;
    	static private volatile boolean instanced = false;
     
    	static public Tmp getInstance() {
    		if (!instanced) {
    			synchronized (Tmp.class) {
    				if (instance == null) {
    					instance = new Tmp();
    					instanced = true;
    				}
    			}
    		}
    		return instance;
    	}
    }
    qui ressemble au l'utilisation du ThreadLocal... en fait, je ne vois pas ce qu'apporte le threadlocal dans ce cas.

    Merci d'avance.

  2. #2
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par lolingman Voir le message
    qui ressemble au l'utilisation du ThreadLocal... en fait, je ne vois pas ce qu'apporte le threadlocal dans ce cas.
    Voir l'article juste au-dessus le lien que tu donnes :
    3.2.3.2. Pourquoi le DCL ne marche pas ?

    En résumé, du point de vue du thread 1 qui entre dans synchronized, tout va bien, l'instance n'existe pas, il va donc la créer.
    Mais du point de vue du thread 2 qui arrive juste à ce moment là, instanced pourrait être true avant que instance soit assigné à non-null, ou bien alors que son constructeur n'est pas terminé.
    Dans ce cas-là, thread 2 va vérifier si instanced est true ou false, va voir true, et donc renvoyer un pointeur null, ou bien un objet qui n'est pas complètement initialisé.

    C'est un désordre de lecture/écriture sur instanced et instance, dû au fait que ces variables sont partagées entre tous les threads, mais leur lecture/écriture n'est pas synchronisée.

    Avec l'utilisation un peu incongrue de ThreadLocal que donne cet article, chaque thread a sa propre version indépendante du contenu de ThreadLocal.get() et ThreadLocal.set(), et il ne peut donc pas y avoir désordre d'écriture/lecture. (=> on peut y stocker le booléen instanced, et vérifier ce booléen à la fois dans le synchronized et hors du synchronized.)

    Autrement dit, ça apporte que ça marche... Mais c'est une écriture un peu compliquée. Souvent, il est juste plus intéressant de créer l'instance au chargement de la classe, ou au moins au début monothreadé du programme, et basta.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 25
    Par défaut
    tu me dis que la thread 1 peut écrire dans instanced avant d'écrire dans instance (d'un point de vue vue mémoire commune), mais avec un ThreadLocal qu'est ce qui rattache le threadlocal et l'instance ?

    Autrement dit, le threadholder va être mis a true, donc son get retourner true, mais est-on sûr que l'instance est bien écrite en entier à ce moment ??

    Je ne comprend toujours pas...

    edit : en fait chaque thread fait son new Tmp ? si c'est le cas je trouve ca bizarre et même dangereux de recréer l'instance alors que potentiellement une autre thread utilise l'instance en la croyant créé auparavant...

  4. #4
    Membre Expert
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Par défaut
    pour suivre ton raisonnement il faudrait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    static public Tmp getInstance() {
    		if (!instanced) {
    			synchronized (Tmp.class) {
    				if (!instanced) {
    mais bof de bof! on a à chaque fois une copie mémoire pour lire la variable volatile l'intérêt est loin d'être évident.
    Par ailleurs je trouve ce problème de l'instanciation paresseuse de l'instance du domaine des actes contre-nature avec les mouches.
    de plus le pattern Singleton tel qu'il est décrit n'est pas une bonne solution dans la majorité des cas.

  5. #5
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par professeur shadoko Voir le message
    pour suivre ton raisonnement il faudrait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    static public Tmp getInstance() {
    		if (!instanced) {
    			synchronized (Tmp.class) {
    				if (!instanced) {
    mais bof de bof! on a à chaque fois une copie mémoire pour lire la variable volatile l'intérêt est loin d'être évident.
    Non, cela ne marche pas*. Le Double Check Lock ne marche pas.

    Le instanced qui est hors du synchronized pourrait être lu true alors que le thread chargé de le mettre à true n'a pas encore fini l'opération globale non-atomique de contrsuire l'instance et mettre instanced à true.
    Cela parce que la lecture/écriture de instanced n'est pas synchronisée.

    * Je dis "ça ne marche pas," je veux dire "la synchronisation n'est pas faite, et un problème peut survenir. Mais c'est rare à l'usage."

    Citation Envoyé par lolingman
    tu me dis que la thread 1 peut écrire dans instanced avant d'écrire dans instance (d'un point de vue vue mémoire commune), mais avec un ThreadLocal qu'est ce qui rattache le threadlocal et l'instance ?
    Rien, ce n'est pas qu'il fait. ThreadLocal enlève le désordre d'écriture de la variable instanced parce que chaque thread a sa variable instanced et ignore celle des autres. Le désordre n'arrive donc pas.

    Donc, on vérifie si l'instance existe, à la connaissance du thread en cours, avec un booléen du thread en cours.
    Si oui, parfait, on renvoie l'instance.
    Si non, on passe dans le code synchronisé pour éviter que plusieurs threads ne le fassent.
    Là, on regarde directement l'instance : est-elle nulle ou pas ? Note qu'on ne regarde cette instance qu'à l'intérieur du bloc synchronisé : lecture/écriture correctement synchronisée.
    S'il existe, ok, on retient dans le thread en cours que l'instance existe, et on la renvoie.
    Si elle n'existe pas, on la crée. On est dans le bloc synchronisé, donc on peut. Puis on retient dans le thread en cours que l'instance existe, et on la renvoie.

    edit : en fait chaque thread fait son new Tmp ?
    Non, juste sa propre variable "est-ce que l'instance existe ?"

    Faire une instance par thread est une autre manière d'aborder le problème, qui a aussi son charme (et qui est bien moins compliquée.) Toutefois, ce n'est pas vraiment ce qu'on appelle un singleton.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    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,

    La solution la plus simple reste celle consistant à utiliser le classloader et le chargement de la classe pour initialiser l'instance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class Singleton {
     
        private final static Singleton INSTANCE = new Singleton();
     
        private Singleton() {
            // empty
        }
     
        public static Singleton getInstance() {
            return INSTANCE;
        }
     
    }
    a++

  7. #7
    Membre Expert
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Non, cela ne marche pas*. Le Double Check Lock ne marche pas.

    Le instanced qui est hors du synchronized pourrait être lu true alors que le thread chargé de le mettre à true n'a pas encore fini l'opération globale non-atomique de contrsuire l'instance et mettre instanced à true.
    Cela parce que la lecture/écriture de instanced n'est pas synchronisée.

    * Je dis "ça ne marche pas," je veux dire "la synchronisation n'est pas faite, et un problème peut survenir. Mais c'est rare à l'usage."
    fait, on renvoie l'instance.
    .
    que DCL ne marche pas je suis au courant: ici si instanced est volatile tu n'as pas exactement le comportement que tu décris.
    dans le bloc synchronized le booleen volatile doit être modifié aprèsla création de l'instance (du coup relation "happens before" garantie depuis 1.5 s'applique), ensuite s'il est modifié toute lecture par un autre thread sera valide.ThreadB ne peut pas lire à true si l'instance n'a pas été créée (ce n'était pas vrai avant la 1.5).
    la question est donc est ce que ThreadB peut avoir dans sa mémoire de ThreadB instanced correct et instance non recopié depuis la mémoire principale: la spec n'est pas claire claire sur ce point
    ceci dit je ne ferais jamais ce truc!

    pour le Singleton je préfère ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class MaChose { // personne ne sait que c'est un singleton
      private static class Singleton {
            public void methode () {
                 ///
            }
      }
      private static final Singleton SINGLA= new Singleton() ;
     
      public MaChose() { }
      public void methode() {
            SINGLA.methode() ;
      }
    }
    le point fondamental: personne ne sait que ça s'appuie sur un singleton! et comme ça on peut changer d'avis!

Discussions similaires

  1. Swing MVC avec singleton, multithreadé ou pas?
    Par faust73 dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 22/09/2014, 20h03
  2. Singleton - multithread - protection donnees - conteneurs stl
    Par sone47 dans le forum Threads & Processus
    Réponses: 8
    Dernier message: 18/01/2013, 11h51
  3. Singleton avec ThreadLocal
    Par christopheJ dans le forum Codes sources à télécharger
    Réponses: 0
    Dernier message: 10/03/2011, 13h43

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