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

Concurrence et multi-thread Java Discussion :

[Astuce][Thread]Utilisation des blocs synchronized


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut [Astuce][Thread]Utilisation des blocs synchronized
    hello,

    je suis bloqué sur l'utilisation du mot clé synchronized... en fait je ne comprend pas comment utiliser les blocs synchronisés...

    je vais essayer d'expliquer ma situation le plus clairement possible.

    j'ai une classe qui implémente Runnable. La méthode run() s'occupe de mettre à jour différents JPanel en fonction de l'état d'un objet (en fait je dessine dans des JPanel selon l'état d'un chronomètre)

    Cependant, une autre méthode de la classe permet d'activer / de désactiver certains JPanel (elle fait un removeAll() puis reconstruit seulement ceux nécessaires)... et donc si le thread exécutant la méthode run() se trouve arrêté au milieu d'une mise à jour, puis qu'ensuite le JPanel sur lequel il était en train de travailler est détruit et n'existe plus, cela me fait des NullPointerException et ensuite plus rien ne fonctionne...

    Je met le code (allégé) des deux méthodes en cause

    méthode run()
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    public void run() {
        interrupted = false;
     
        while (!interrupted) {
          byte lesHeures   = CHRONO.getHeures();
          byte lesMinutes  = CHRONO.getMinutes();
          byte lesSecondes = CHRONO.getSecondes();
          int  lesMillis   = CHRONO.getMillis();
     
          if ((h != null) && withHours) {
            synchronized (h) {
              h[0].setValue((byte) (lesHeures / 10));
              h[1].setValue((byte) (lesHeures % 10));
            }
          }
     
          if ((min != null) && withMin) {
            synchronized (min) {
              min[0].setValue((byte) (lesMinutes / 10));
              min[1].setValue((byte) (lesMinutes % 10));
            }
          }
     
          if ((sec != null) && withSec) {
            synchronized (sec) {
              sec[0].setValue((byte) (lesSecondes / 10));
              sec[1].setValue((byte) (lesSecondes % 10));
            }
          }
     
          if ((ms != null) && withMS) {
            synchronized (ms) {
              ms[0].setValue((byte) (lesMillis / 100));
     
              byte temp = (byte) (lesMillis % 100);
              ms[1].setValue((byte) (temp / 10));
              ms[2].setValue((byte) (temp % 10));
            }
          }
     
          try {
            Thread.sleep(1000 / FPS);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    méthode qui active / détruit certains JPanel

    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
      public void recreerLesDigits() {
        removeAll();
        h     = null;
        min   = null;
        sec   = null;
        ms    = null;
     
        if (withHours) {
          h = new Digit[2];
          for (int i = 0; i < h.length; i++) {
            h[i] = new Digit();
            h[i].setLargeurSeg(largGrSeg);
            //etc
          }
        }
     
        if (withMin) {
          min = new Digit[2];
          for (int i = 0; i < min.length; i++) {
            min[i] = new Digit();
            min[i].setLargeurSeg(largGrSeg);
            //etc
          }
          memo += ((2 * longuGrSeg) + (6 * largGrSeg));
          nGroupes++;
        }
     
        if (withSec) {
          sec = new Digit[2];
          for (int i = 0; i < sec.length; i++) {
            sec[i] = new Digit();
            sec[i].setLargeurSeg(largGrSeg);
            // etc
          }
        }
     
        if (withMS) {
          ms = new Digit[3];
     
          for (int i = 0; i < ms.length; i++) {
            ms[i] = new Digit();
            ms[i].setLargeurSeg(largPeSeg);
            //etc
          }
        }
      }
    Si quelqu'un pouvait me dire comment dispatcher mes blocs synchronisés pour éviter les NullPointer (bon je sais qu'on pourrait utiliser des try/catch mais je voudrais vraiment comprendre le synchronized )

    Et si ça intéresse quelqu'un je peux mettre en ligne un zip avec le fichier projet Eclipse 3.0 et toutes les sources (si vous avez envie de pouvoir tester en "live")

    Merci de votre aide !

  2. #2
    Membre émérite
    Avatar de xavlours
    Inscrit en
    Février 2004
    Messages
    1 832
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 1 832
    Points : 2 410
    Points
    2 410
    Par défaut
    hoïdidiho
    moi je dirais que ton run() est pas mal, mais dans ton recreerLesdigits() je mettrais toute action sur les pointeurs h min sec ms en bloc synchronized. Genre :
    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
    if (withHours) { 
     
          synchronized(h) {
     
              h = new Digit[2]; 
              for (int i = 0; i < h.length; i++) { 
                  h[i] = new Digit(); 
                  h[i].setLargeurSeg(largGrSeg); 
                  //etc 
              }
     
          } 
    } 
    else {
             synchronized(h) {
                  h = null;
              }
         }
    Il y a des chances pour que ca marche.
    Quant au mot cle synchronized je crois que l'objet que tu mets a l'interieur ne sert que de clé. Il y a des langages ou les mutex (mutual exclusion) sont identifies par des chaines de caracteres, en java ils sont identifies par des objets. il y a donc au maximum un mutex par objet.
    Mais tu peux tres bien modifier ton tableau h au milieu d'un bloc synchronisé sur monOursEnPeluche(par exemple), tant que tous les autres threads se synchronisent sur le meme objet pour modifier h.
    Mais pourquoi synchronized(this) pour wait et notify?Je sais pas vraiment, je suppose.

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    652
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2002
    Messages : 652
    Points : 1 151
    Points
    1 151
    Par défaut
    le mot-clé synchronized permet de poser un verrou sur une méthode ou sur une référence.

    Quand tu pose un verrou sur une référence, il est impératif que celle-ci ne soit pas null sinon c'est plantage assuré.

    Un bloc synchronisé interdit l'accès à la référence par tous les autres Thread, y compris le Thread Main.

    Qui appel explicitement ta méthode recreerLesDigits() ?

  4. #4
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Citation Envoyé par Alwin
    le mot-clé synchronized permet de poser un verrou sur une méthode ou sur une référence.

    Quand tu pose un verrou sur une référence, il est impératif que celle-ci ne soit pas null sinon c'est plantage assuré.

    Un bloc synchronisé interdit l'accès à la référence par tous les autres Thread, y compris le Thread Main.

    Qui appel explicitement ta méthode recreerLesDigits() ?
    En fait synchronized ne marche que pour les references, normalement les moniteur de Hoare ont une entree en mutex et ensuite on s'enregistre dans la file pour acceder a une methode...
    En java leur implementation fait que le mot cle synchronized assure un acces au bloc (ou a la methode) en mutex pour un objet.

    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public synchronized method()
    {...}
     
    synchronized(this)
    {...}
    Utilise le meme moniteur et il n'est pas possible de rentrer dans l'une si un autre thread est dans l'autre ..

    Bulbo

  5. #5
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    bjr,

    merci a tous de vous être penchés sur mon problème

    Citation Envoyé par xavlours
    hoïdidiho
    moi je dirais que ton run() est pas mal, mais dans ton recreerLesdigits() je mettrais toute action sur les pointeurs h min sec ms en bloc synchronized.
    bin le problème est que cela fait pas mal de nullpointer en faisant comme ça...
    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
     
    if (withHours) { 
      // si h était null -> nullpointerexception
      synchronized(h) { 
        h = new Digit[2]; 
          for (int i = 0; i < h.length; i++) { 
            h[i] = new Digit(); 
            h[i].setLargeurSeg(largGrSeg); 
            //etc 
          } 
       } 
    } 
    else { 
      // si h était null -> nullpointerexception
      synchronized(h) { 
        h = null; 
      } 
    }


    Citation Envoyé par Alwin
    Qui appel explicitement ta méthode recreerLesDigits() ?
    la méthode recreerLesDigits() est appelée lorsque l'on presse sur le bouton "ok" ou "appliquer" d'un JDialog servant à modifier les paramètres de l'afficheur.

    Concernant les références, j'avais déjà remarqué que si la référence est nulle lorsque l'on place le bloc synchronized cela fait des nullpointer...




    Citation Envoyé par bulbo
    En fait synchronized ne marche que pour les references, normalement les moniteur de Hoare ont une entree en mutex et ensuite on s'enregistre dans la file pour acceder a une methode...
    euh... et en français ça donne quoi ?

  6. #6
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    bon je crois que je vais quand même mettre online le projet dans son état actuel

    Chronometre.zip, 44Ko (avec jar + sources)

    vous pourrez mieux vous rendre compte du problème comme ça (enfin je pense)

  7. #7
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Bon j'ai reussi a le faire tourner sans NullPointer (et sans try/catch bien sur )

    Explications (on va essayer d'etre clair):

    Ton probleme vient du fait que tu as des synchronized sur je ne sais pas combien de variables..
    Dans ton algo tu fais un recreerLesDigits qui marche pour tout les digits en une fois..

    Simplifie toi la vie, fait un synchronized sur this et seulement sur ca...

    Dans ton run au lieu d'avoir un bloc synchronized par segment, tu en fait un seul qui englobe tout les segments...

    Pour eviter les problemes tu dois aussi declarer synchronized les methodes qui changent l'affichage des segments comme recreerLesDigits et les withHours, withMin ..

    Avec ca plus de probleme. Deux threads ne peuvent pas modifier en meme temps les Digits ce qui t'assure la coherence des donnees que tu utilises ..

    Tu peux aussi garder les synchronized sur differentes variables si tu y tiens mais cela va multiplier les entrees/sorties de mutex (ce qui est long), va t'obliger a mettre des bloc synchronized un peu partout et pour faire bonne mesure il va aussi falloir que tu fasses du double-check ..

    Bulbo

  8. #8
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    ok, je comprend un peu mieux...

    donc en fait je déclare mes méthodes run() et recreerLesDigits() synchronized, ou bien je fais un gros bloc synchronized(this){} qui englobe toutes les instructions des-dites méthodes ? ça revient au même, non ?

    mais bon, lorsque l'on fait un synchronized(this) , tout les objets de la classe sont synchronisés ou bien juste l'instance courante (le this) ?

  9. #9
    Membre expérimenté Avatar de yann2
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 897
    Points : 1 635
    Points
    1 635
    Par défaut
    mais bon, lorsque l'on fait un synchronized(this) , tout les objets de la classe sont synchronisés ou bien juste l'instance courante (le this) ?
    Ben seulement l'instance courante.
    Mais du coup ça va bloquer l'appel aux méthodes d'instance qui sont synchronized (et les blocs synchronized(this){}). Donc pas de pb.

  10. #10
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut


    alors je teste et je reviens

  11. #11
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    euh.... bulbo ?

    tu pourrais m'envoyer le projet avec tes modifications ? histoire que je puisse voir ce que tu as changé...

    parce qu'en déclarant les 2 méthodes synchronized, ça plante pas mal...

  12. #12
    Membre expérimenté Avatar de yann2
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 897
    Points : 1 635
    Points
    1 635
    Par défaut
    Normal, la méthode run ne peut pas être synchronized (elle vient de l'interface Runnable ou de la classe Thread).

    Faut faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void run() {
       synchronized(this) {
         ....
       }
    }
    bon courage

  13. #13
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    bon apparement je suis arrivé à enlever les NullPointer (après une trentaine de tests je pense que c'est à peu près bon).

    j'ai placé le bloc synchronized(this) autour du traitement de mes objets critiques:
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    public void run() {
        interrupted = false;
     
        while (!interrupted) {
          byte lesHeures   = CHRONO.getHeures();
          byte lesMinutes  = CHRONO.getMinutes();
          byte lesSecondes = CHRONO.getSecondes();
          int  lesMillis   = CHRONO.getMillis();
     
     
          synchronized (this) {  // <--- de là
            if ((h != null) && withHours) {
              h[0].setValue((byte) (lesHeures / 10));
              h[1].setValue((byte) (lesHeures % 10));
            }
     
            if ((min != null) && withMin) {
              min[0].setValue((byte) (lesMinutes / 10));
              min[1].setValue((byte) (lesMinutes % 10));
            }
     
            if ((sec != null) && withSec) {
              sec[0].setValue((byte) (lesSecondes / 10));
              sec[1].setValue((byte) (lesSecondes % 10));
            }
     
            if ((ms != null) && withMS) {
              ms[0].setValue((byte) (lesMillis / 100));
     
              byte temp = (byte) (lesMillis % 100);
              ms[1].setValue((byte) (temp / 10));
              ms[2].setValue((byte) (temp % 10));
            }
          } // <--- jusqu'à de là ;-)
     
          try {
            Thread.sleep(1000 / FPS);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    mais il en reste encore un... si je ferme la fenêtre pendant que le Thread est en route, re-NullPointer...

    bon j'admet que c'est un détail, mais cela traduit sûrement une erreur de conception de ma part...

  14. #14
    Membre expérimenté Avatar de yann2
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 897
    Points : 1 635
    Points
    1 635
    Par défaut
    mais il en reste encore un... si je ferme la fenêtre pendant que le Thread est en route, re-NullPointer...
    Normal, tu n'as plus tes composants graphiques, et ton thread continue de tourner jusquà la fin.

    Tu peux synchroniser ton setVisible(false) ou arréter ton thread avant de fermer la fenêtre.

  15. #15
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    OK tip top !

    ça demande quand même pas mal de reflexion le développement multi-thread !

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

Discussions similaires

  1. [OL-2013] Utiliser des blocs de type QuickPart dans une réponse
    Par lodan dans le forum Outlook
    Réponses: 2
    Dernier message: 07/11/2014, 15h42
  2. Utilisation des blocs fonction
    Par celtic29 dans le forum Simulink
    Réponses: 7
    Dernier message: 08/06/2012, 21h22
  3. Utilisation des blocs buffer et unbuffer
    Par aguysfr dans le forum Simulink
    Réponses: 0
    Dernier message: 29/09/2008, 21h43
  4. Utilisation des threads
    Par Valinor dans le forum Linux
    Réponses: 2
    Dernier message: 30/11/2005, 16h41
  5. Utilisations des Threads
    Par phoenix440 dans le forum Réseau
    Réponses: 15
    Dernier message: 21/08/2005, 17h19

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