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 :

synchronisation, atomicité et volatilité


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut synchronisation, atomicité et volatilité
    Bien que j'ai écrit un tutoriel sur la synchronisation en Java, il reste des petites questions auxquelles je n'ai pas de réponse (et dont je ne parle évidemment pas dans le tutoriel, à la limite on peut s'en passer).

    Ma question pourrait se résumer à ceci (où s est une variable partagée entre 2 threads) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //Thread 1
    s = "abc";
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //Thread 2
    s = "def";
    Le fait que ça soit un String n'a aucune importance, ma question concerne l'affectation d'un Object (pas d'un type primitif) à une variable.

    Est-ce qu'une affectation d'objet a besoin d'être synchronisée?
    Vous me direz, dans le doute, autant le faire. Mais justement, je veux lever le doute.

    Pöurquoi ma question concerne uniquement les Object et non les types primitifs? Tout simplement parce que si c'est un long ou un double, par exemple, on ne peut pas se passer de la synchronisation (l'affectation change les 32 bits de poids forts, puis les 32 bits de poids faible -ou le contraire, peu importe-).

    Mais à priori, l'implantation des références est un int, non?

    Faut-il en plus ajouter "volatile"? Est-ce nécessaire? Est-ce suffisant?

    Et, si la réponse est "non, pas besoin de synchronisation", est-ce vrai aussi pour les multiprocesseurs?

    Enfin, est-ce que cela peut poser d'autres problèmes de ne pas synchroniser une affectation d'objets, par exemple par une réorganisation d'écritures / lectures par le compilateur?

  2. #2
    Membre chevronné Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Par défaut
    L'exemple que tu donnes est l'exemple typique où il faut synchroniser, il me semble : c'est l'écriture d'une même variable par deux threads différents.

    Cependant je ne comprends pas, tu as déjà posé le même genre de question il y a 2 mois. Nous y avions relevé des éléments pondérateurs des grands principes... Si la réponse brutale est oui, il faut synchroniser, la réponse pratique est quelquesfois non . En ce domaine, le mieux est vraiment l'ennemi du bien, c'est ce qui est difficile.

    Par rapport à tous ces débats, qu'est-ce qu'il y a de différent dans ton problème ?

  3. #3
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par spekal
    L'exemple que tu donnes est l'exemple typique où il faut synchroniser, il me semble : c'est l'écriture d'une même variable par deux threads différents.
    Je ne pense pas que ça soit un exemple typique où il faut synchroniser...
    Là où c'est typique, c'est pour les "test and set"...

    Citation Envoyé par spekal
    Cependant je ne comprends pas, tu as déjà posé le même genre de question il y a 2 mois.
    LOL
    Effectivement, tu as raison. Je me rappelais avoir posé une question similaire, mais je ne pensais pas que mes deux questions se ressemblaient autant

    Citation Envoyé par spekal
    Nous y avions relevé des éléments pondérateurs des grands principes... Si la réponse brutale est oui, il faut synchroniser, la réponse pratique est quelquesfois non .
    Oui, mais justement, j'aimerais bien savoir précisément dans quels cas "oui" et dans quels cas "non". Et surtout pourquoi.

    Mais il semblerait que je ne puisse pas comprendre la réponse à cette question sans vraiment approfondir le fonctionnement du bytecode.

    Citation Envoyé par spekal
    Par rapport à tous ces débats, qu'est-ce qu'il y a de différent dans ton problème ?
    C'est juste qu'entre temps, j'ai eu des cours de systèmes concurrents, où j'ai compris beaucoup de choses concernant la synchronisation, mais cette question (qui est je dirais un détail d'implémentation) est resté dans un coin de ma tête sans réponse.


    Et ce qui me met encore plus le doute, c'est la classe EventListListener de la JDK. La ligne en gras n'est pas synchronisée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        public <T extends EventListener> T[] getListeners(Class<T> t) {
    	Object[] lList = listenerList;
    	int n = getListenerCount(lList, t); 
            T[] result = (T[])Array.newInstance(t, n); 
    	int j = 0; 
    	for (int i = lList.length-2; i>=0; i-=2) {
    	    if (lList[i] == t) {
    		result[j++] = (T)lList[i+1];
    	    }
    	}
    	return result;   
        }
    Finalement, je pense que la réponse à mon problème est "Si on ne synchronise pas cette affectation, ça n'est pas grave -pas de concurrence à ce niveau-, mais par contre, les autres threads ne seraient pas avertis aussitôt -indéterminisme de mise à jour des copies locales- de la nouvelle valeur"...

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


    Pour les types long et double l'écriture n'est pas forcément découpé en deux : chaque implémentation de la JVM est libre de faire ce quelle veux... mais cela revient au même car il faut considérer cela comme des opérations non-atomique...

    17.7 Non-atomic Treatment of double and long




    Pour revenir à ton problème... je ne m'y connais pas trop en atomicité mais je pense que l'utilisation de volatile est nécessaire afin d'être sûr que le thread utilise bien la bonne valeur et qu'il n'y a pas "d'optimisation" qui font qu'on utilise une "copie" plus ancienne...


    De plus les problèmes ne se poseront pas sur l'affectation elle-même (qui devrait toujours fonctionner je pense) mais sur le reste de ton code. Par exemple si tu as un code du style :
    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
    18
    19
    20
    21
    public class Test {
     
    	private String s; // shared
     
    	public void setS(String s) {
    		this.s = s;		
    	}
     
    	public void doSomething() {
     
    		if (s==null) {
    			// Traitement spécifique a null
    		} else {
    			Thread.yield();
    			// On suppose que s n'est pas null :
    			s.trim(); // peut générer un NullPointerException
    		}
     
    	}
     
    }
    Si les appels à setS() depuis différents threads ne poseront pas de problème, par contre on ne peut pas utiliser s directement dans les autres méthodes (comme doSomething() par exemple) car elle est susceptible de changer entre deux de ces utilisations (dans le code ci-dessus Thread.yield() permet d'amplifier ce phénomène), Dans ces cas là il est fortement préférable d'utiliser une copie locale qui ne serait pas impacté par une modification de s depuis un autre thread :

    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 void doSomething() {
     
    		// On copie 's' dans ' localS' et on n'utilise QUE cette dernière
    		String localS = s;
     
    		if (localS==null) {
    			// Traitement spécifique a null
    		} else {
    			Thread.yield();
    			// On est sûr que localS n'est pas null :
    			localS.trim();
    		}
     
    	}
    Ici on utilise une copie de l'attribut et on ne travaille que la copie. Les modifications de s depuis d'autres threads ne poseront donc pas de problème puisqu'on utilisera toujours la même valeur pendant tout le déroulement de la méthode...





    Citation Envoyé par ®om
    Et ce qui me met encore plus le doute, c'est la classe EventListListener de la JDK. La ligne en gras n'est pas synchronisée :
    Je te rappelle que l'API Swing est mono-thread (sauf quelques exceptions) et toutes ses méthodes DEVRAIENT être appelé dans l'EDT seulement : il n'y a donc aucun besoin de synchronisation



    a++

  5. #5
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par adiGuba
    Je te rappelle que l'API Swing est mono-thread (sauf quelques exceptions) et toutes ses méthodes DEVRAIENT être appelé dans l'EDT seulement : il n'y a donc aucun besoin de synchronisation
    Le problème, c'est qu'on utilise la classe EventListenerList pour faire nos propres listeners (non?).

    Et ce qu'on écoute, ça peut très bien se passer en dehors de l'EDT...

  6. #6
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Dans le lien que tu m'as donné , il y a une partie de la réponse à ma question:
    Writes to and reads of references are always atomic,
    !!!

    Cool merci

  7. #7
    Membre chevronné Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Par défaut
    Citation Envoyé par ®om
    Oui, mais justement, j'aimerais bien savoir précisément dans quels cas "oui" et dans quels cas "non". Et surtout pourquoi.
    Je pense qu'en ce domaine il ne faut pas réfléchir dans le cas général, mais dans le cas de ton appli, ou module.

    La règle d'or est qu'il ne doit pas y avoir d'accés simultanés en écriture et lecture, qui risquent de rendre incohérent ou invalide une valeur.

    Ces risques se découvrent par la reflexion (réflexion humaine, hein, pas réflexion java), à partir de la compréhension des algorythmes ; je ne connais pas d'autres moyens. À ce sujet les jeux de tests à la mode XP sont de la foutaise.

    Donc, pour moi, il n'y a pas de garantie à tous les coups qu'un logiciel est protégé au regard du multithread. Il est protégé seulement dans certains cas, que l'on peut expliciter. Le cas le plus classique est évidemment le mode multitâche dans le style unix (et déjà ce n'est pas si facile).

    Concernant le EventListener, je ne trouve pas que ce code soit de la meilleure qualité... en général, c'est mieux dans le jdk...

    Ton analyse est le plus probablement celle qu'à faite ceux qui ont pondu ça, et effectivement, elle tient bien le choc si un thread concurent ajoute un autre listener. Par contre, si, par malheur, le thread concurent retire un listener, il me semble qu'on abouti à une liste comportant des éléments à null... pas catastrophique, mais pas très éléguant non plus... On a au moins une incohérence sémantique, puisque si je demande la liste des listeners, c'est pas pour en avoir à null...

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par spekal
    Concernant le EventListener, je ne trouve pas que ce code soit de la meilleure qualité... en général, c'est mieux dans le jdk...
    Comment ça? ça c'est le code source de EventListenerList dans le JDK, que lui reproches-tu?

    Citation Envoyé par spekal
    Ton analyse est le plus probablement celle qu'à faite ceux qui ont pondu ça, et effectivement, elle tient bien le choc si un thread concurent ajoute un autre listener. Par contre, si, par malheur, le thread concurent retire un listener, il me semble qu'on abouti à une liste comportant des éléments à null... pas catastrophique, mais pas très éléguant non plus... On a au moins une incohérence sémantique, puisque si je demande la liste des listeners, c'est pas pour en avoir à null...
    Bah non, si tu retires un listener, la liste (le tableau) des écouteurs étant recopiée de manière synchronisée (add et remove sont synchronized), il n'y a pas de problème...

  9. #9
    Membre chevronné Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Par défaut
    Citation Envoyé par ®om
    Bah non, si tu retires un listener, la liste (le tableau) des écouteurs étant recopiée de manière synchronisée (add et remove sont synchronized), il n'y a pas de problème...
    Oui, effectivement... j'ai fini par aller voir tout le code de ce EventListenerList (et non pas EventListListener comme tu nous le dit au départ ), et j'admets. Mais enfin, je trouve que ce n'est pas du bon codage, ou alors il y a des raisons subtiles que je ne connais pas... pourquoi n'ont-ils pas employés de bêtes ArrayList ? -> peut être que c'est un code qui date d'avant ; je faisais comme ça, effectivement, en java 1.1...

Discussions similaires

  1. synchronisation de deux DBLookUPComboBox
    Par frede dans le forum Bases de données
    Réponses: 2
    Dernier message: 20/02/2004, 08h32
  2. Synchronisation de thread
    Par declencher dans le forum Langage
    Réponses: 2
    Dernier message: 07/01/2004, 10h28
  3. Probleme Synchronisation modem Sagem Fast 800
    Par -PiKo- dans le forum Matériel
    Réponses: 4
    Dernier message: 03/01/2004, 15h36
  4. Synchronisation verticale
    Par hs_dino dans le forum OpenGL
    Réponses: 2
    Dernier message: 28/09/2003, 09h35
  5. Synchronisation de base de données locale/distante Internet
    Par StefC30 dans le forum Développement
    Réponses: 3
    Dernier message: 25/07/2003, 14h47

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