numérotation automatique avec synchronized
2 participants
Programmation Concurrente (2016) :: Questions/réponses (french or english) :: Questions sur le cours (semaine 3)
Page 1 sur 1
numérotation automatique avec synchronized
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 :
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) :
$ 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 :
$ 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 :
$ 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.
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();
}
}
}
$ 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);
}
}
$ 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);
}
}
}
$ 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
Re: numérotation automatique avec synchronized
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
Car vous ne passez pas par un new. Je vous propose une autre implémentation de votre classe:
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...
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...
Re: numérotation automatique avec synchronized
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 :
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.
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++;
- 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
Re: numérotation automatique avec synchronized
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.
Cela dit, je trouve que le compilateur devrait râler au moment de l'initialisation sans passer par le constructeur.
Bien cordialement.
Programmation Concurrente (2016) :: Questions/réponses (french or english) :: Questions sur le cours (semaine 3)
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum