Programmation Concurrente (2016)

numérotation automatique avec synchronized

Aller en bas

numérotation automatique avec synchronized

Message par lambda le Mer Sep 26, 2018 10:41 pm

Bonjour,

En testant la numérotation automatique présentée dans la vidéo 026, j'aboutis à un comportement étrange.

Je considère un classe de la forme :

Code:

class A implements Runnable {
    private int id;
    private static int idGenerator = 0;
    private static Object mutex = new Object ();

     A (){
        synchronized (mutex){
           id = idGenerator++;   
           System.out.println(id);
      }
   }
   public void run(){}
}

Puisque, le constructeur Java s'exécute de manière séquentielle,
Il n'est pas possible de tester la synchronisation dans le constructeur.

Je déplace donc le bloc synchronized dans de la méthode run, ce qui, à priori, ne devrait pas changer le comportement (la numérotation automatique) :

Code:

class A implements Runnable {
    private int id;
    private static int idGenerator = 0;
    private static Object mutex = new Object ();

   A (){}
    
    public void run(){
       synchronized (mutex){
            id = idGenerator++;   
            System.out.println(id);
       }
    }
}

public class M {
    static final int NB = 10000;
    public static void main(String [] args) {
        for (int i = 0; i < NB;i++){
           new Thread(new A()).start();
        }
    }
}
Constat, ça marche...
$ java M
0
...
9999
$

Or, dans la vidéo 026, à 3'04, vous précisez :
"je n'ai pas utilisé le moniteur de this, pour montrer qu'on peut faire différemment".

Je teste donc le code précèdent en me synchronisant sur this :
Code:

   public void run(){
       synchronized (this){
            id = idGenerator++;   
            System.out.println(id);
       }
   }
Et là, paf, ça ne marche pas :

$ java M
0
...
9977
$ java M
0
...
9982

J'en déduis que le mutex doit être static en sorte que les instances de la classe puissent se synchroniser sur lui (par opposition au this qui, si j'ai bien compris, désigne l'objet courant).

Est-ce bien là le problème ?

Je tente alors une autre variante.
Je prends une variable static de type Integer, qui donc a un verrou.
Je me synchronise sur lui :
Code:

class A implements Runnable {
    private int id;
    private static Integer idGenerator = 0;  

    A (){}
    
    public void run(){
       synchronized (idGenerator){
            id = idGenerator++;   
            System.out.println(id);
       }
    }
}
Et curieusement, ça ne marche pas !


$ java M
0
...
9998
$ java M
0
...
9995
$ java M
0
...
9997

Je me demande donc, en quoi ce dernier exemple est-il erroné...
   

Merci
Cordialement.

lambda

Posts : 2
Join date : 12/09/2018

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: numérotation automatique avec synchronized

Message par Admin le Lun Oct 01, 2018 9:02 pm

Bonjour... Il y a plein de questions dans votre post. Je vais essayer de répondre à toutes.

1) dans le cas présent, les constructeurs sont exécutés par main et comme il n'y en n'a qu'un seul, en effet la protection peut paraître inutile. Mais dans le cas général, c'est plus sûr. Cela dit, vous voyez déjà qu'avec les commutations, quand vous vous synchronisez sur this (cf votre 2eme exemple), cela peut ne pas fonctionner.

2) en 3'06, je me suis mal exprimé et c'est en effet confus car dans le cas présent, la synchronisation sur this n'apporte pas la protection souhaitée puisque chaque objet possède son propre "This". En gros, la synchronisation sur This est un peu équivalente à une synchronisation sur une méthode... sauf qu'on peu en réduire la portée à une portion de la méthode. Ce que je veux dire c'est que le synhronized peut ne pas porter que sur "this" (mais aussi sur d'autres objets). Mais c'est maladroitement formulé je vous l'avoue. Mais vous avez visiblement bien compris cela puisque vous déduisez que ce qui est important, c'est le "static" (ce que je confirme).

3) le troisième exemple peut laisser dubitatif car Interger hérite de Number qui hérite lui-même de Object. Mais vous ne passez pas par un constructeur et je ne suis pas certain de ce qui se passe quand vous faites

Code:
 private static Integer idGenerator = 0;

Car vous ne passez pas par un new. Je vous propose une autre implémentation de votre classe:

Code:
class A implements Runnable {
    private int id;
    private static Integer idGenerator = new Integer(0);  

    A (){}
    
    public void run(){
       synchronized (idGenerator){
            id = idGenerator++;  
            System.out.println(id);
       }
    }
}

Dites moi si cela fonctionne comme ça... car cela compile. Je pense personnellement que oui. Mais je reste quand même perplexe que Java accepte l'affectation sans autre forme de procès (dans votre première version qui compile aussi chez moi;-).

En espérant avoir répondu à vos questions...

Admin
Admin

Posts : 55
Join date : 24/08/2016

Voir le profil de l'utilisateur http://3i001-2016.forumactif.org

Revenir en haut Aller en bas

Re: numérotation automatique avec synchronized

Message par lambda le Mar Oct 02, 2018 11:41 am

Bonjour,
Merci pour vos réponses. Tout est clair maintenant et, pour revenir à la 3ème question, je crois avoir compris d'où vient mon erreur.

Suite à vos remarques sur le constucteur de Integer, j'ai réalisé que les instances d'Integer sont immutables
(public final class Integer extends Number).

Donc, lorsque j'écris :
Code:
idGenerator++;
ça sous-entend peut-être quelque chose comme :
Code:
idGenerator = new Integer (idGenerator.intValue() + 1);

Or, comme vous l'avez indiqué dans le cours, la référence sur l'objet "mutex" doit être stable... Ici, ce n'est (peut-être) pas (toujours) le cas, d'où le bug de synchronisation...

Encore merci pour ces précisions.
Cordialement.

lambda

Posts : 2
Join date : 12/09/2018

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: numérotation automatique avec synchronized

Message par Admin le Mar Oct 02, 2018 7:41 pm

OK. Et merci pour votre remarque sur Integer. En effet, le coté immutable explique bien des choses. Autant j'ai l'habitude en Objective-C et Swift (on a très vite intérêt à les utiliser pour gérer proprement la mémoire), autant je n'avais pas joué avec ces aspects là dans Java.

Cela dit, je trouve que le compilateur devrait râler au moment de l'initialisation sans passer par le constructeur.

Bien cordialement.

Admin
Admin

Posts : 55
Join date : 24/08/2016

Voir le profil de l'utilisateur http://3i001-2016.forumactif.org

Revenir en haut Aller en bas

Re: numérotation automatique avec synchronized

Message par Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum