OVH Cloud OVH Cloud

Synchronisation sur un int.

10 réponses
Avatar
Rémi Cocula
J'ai remarqué que l'on ne peut pas écrire quelque chose comme :

int i = 0;

synchronized (i) {
i++;
}

Cela veut-il dire que la synchonisation sur une variable d'un type primitif
n'a aucun sens ?

10 réponses

Avatar
bruno conductier
Pour moi ca voudrait surtout dire que Java n'est pas un langage TOUT objet :o)
puisque selon la JSL
http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html

Each object has an associated lock (§17.13), which is used by synchronized
methods (§8.4.3) and the synchronized statement (§14.18) to provide control over
concurrent access to state by multiple threads (§17.12).

Si donc tu ne peux utiliser de types primitifs comme argument de ton bloc
synchronized c'est qu'ils ne sont pas des objets.

En ce qui concerne ta derniere remarque, il faut peut etre reconsiderer le fait
que tu synchronises l'acces a l'etat d'UN objet plutot que l'acces a une
variable particuliere ?!

A priori, si ta volonte est de synchroniser les seuls acces a une meme variable
(sans locker toutes les autres methodes synchronized de l'objet), rien ne
t'empeche d'utiliser une variable d'instance (dediee ou non a cet usage) de type
objet comme lock.

Une autre approche serait d'utiliser des classes Integer gerant la
synchronization telles les SynchronizedVariable de la librairie de Doug Lea
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
(les classes Wrappers Java java.lang.Integer etant inutiles car immutables :o( )

Bruno

Rémi Cocula wrote:
J'ai remarqué que l'on ne peut pas écrire quelque chose comme :

int i = 0;

synchronized (i) {
i++;
}

Cela veut-il dire que la synchonisation sur une variable d'un type primitif
n'a aucun sens ?



Avatar
Rémi Cocula
bruno conductier wrote:

Pour moi ca voudrait surtout dire que Java n'est pas un langage TOUT objet
:o) puisque selon la JSL

http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html


Each object has an associated lock (§17.13), which is used by synchronized
methods (§8.4.3) and the synchronized statement (§14.18) to provide
control over concurrent access to state by multiple threads (§17.12).

Si donc tu ne peux utiliser de types primitifs comme argument de ton bloc
synchronized c'est qu'ils ne sont pas des objets.


Effectivement les primitifs ne sont pas des objets.


En ce qui concerne ta derniere remarque, il faut peut etre reconsiderer le
fait que tu synchronises l'acces a l'etat d'UN objet plutot que l'acces a
une variable particuliere ?!

A priori, si ta volonte est de synchroniser les seuls acces a une meme
variable (sans locker toutes les autres methodes synchronized de l'objet),
rien ne t'empeche d'utiliser une variable d'instance (dediee ou non a cet
usage) de type objet comme lock.

Une autre approche serait d'utiliser des classes Integer gerant la
synchronization telles les SynchronizedVariable de la librairie de Doug
Lea


Soit. Je peux utiliser un java.lang.Integer au lieu de mon int.
Mais ma question portait surtout sur le fait de mettre en place une
synchronisation pour un simple int. Je veux dire un int (comme tout type
primitif) n'est il pas par nature thread-safe ?

Avatar
nioubi
Rémi Cocula wrote:
Je veux dire un int (comme tout type
primitif) n'est il pas par nature thread-safe ?


Bonjour,

Ca n'est pas une question de nature de la "chose" (extension du concept
objet aux non-objets ...) accédée, mais de nature des opérations
concurrentes effectuées dessus : si plusieurs threads font des lectures
et écritures concurrentes sur une variable, objet ou pritive, les accès
/doivent/ être gardés afin que l'état de la variable reste cohérent.

Après, le modèle de synchro à choisir dépendra de l'utilisation et de la
situation : exclusion mutuelle, écrivain-lecteurs,
(producteur-consommateur).

Avatar
bruno conductier
Cf. "Synchronization and the Java Memory Model" extrait du bouquin de Doug Lea
http://gee.cs.oswego.edu/dl/cpj/jmm.html en particulier le passage sur la notion
d'atomicite

Accesses and updates to the memory cells corresponding to fields of any type
except long or double are guaranteed to be atomic. This includes fields serving
as references to other objects. Additionally, atomicity extends to volatile long
and double. (Even though non-volatile longs and doubles are not guaranteed
atomic, they are of course allowed to be.)

Atomicity guarantees ensure that when a non-long/double field is used in an
expression, you will obtain either its initial value or some value that was
written by some thread, but not some jumble of bits resulting from two or more
threads both trying to write values at the same time. However, as seen below,
atomicity alone does not guarantee that you will get the value most recently
written by any thread.

La derniere phrase devrait repondre a ton interrogation.

Bruno

Rémi Cocula wrote:
Mais ma question portait surtout sur le fait de mettre en place une
synchronisation pour un simple int. Je veux dire un int (comme tout type
primitif) n'est il pas par nature thread-safe ?


Avatar
Rémi Cocula
bruno conductier wrote:


La derniere phrase devrait repondre a ton interrogation.



merci

Avatar
James Kanze
Rémi Cocula wrote:
bruno conductier wrote:


Pour moi ca voudrait surtout dire que Java n'est pas un
langage TOUT objet :o) puisque selon la JSL





http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html


Each object has an associated lock (§17.13), which is used by
synchronized methods (§8.4.3) and the synchronized statement
(§14.18) to provide control over concurrent access to state by
multiple threads (§17.12).



Si donc tu ne peux utiliser de types primitifs comme argument
de ton bloc synchronized c'est qu'ils ne sont pas des objets.



Effectivement les primitifs ne sont pas des objets.


En ce qui concerne ta derniere remarque, il faut peut etre
reconsiderer le fait que tu synchronises l'acces a l'etat d'UN
objet plutot que l'acces a une variable particuliere ?!



En fait, tu ne synchronises jamais un objet, tu synchronises des
blocs de code. Parfois, il peut être commode d'utiliser un objet
existant ; la plupart du temps, je constate que j'alloue un
objet (de type Object) exprès pour le faire. En fait, ça aurait
été bien plus logique d'avoir un objet d'un type spécial (Lock,
ou Synchronizer, ou ...), et ne pas charger tous les types avec
quelque chose qui ne leur sert pour ainsi dire jamais.

A priori, si ta volonte est de synchroniser les seuls acces a
une meme variable (sans locker toutes les autres methodes
synchronized de l'objet), rien ne t'empeche d'utiliser une
variable d'instance (dediee ou non a cet usage) de type objet
comme lock.



Tu ne synchronises pas « l'accès à une variable ». Tu
synchronises un bloc de code. Ensuite, c'est à toi de s'assurer
que tous les accès aux variables qu'il faut soient synchronisés
avec le même objet de vérouillage ; comme j'ai dit, ça signifie
la plupart du temps un objet exprès pour le vérouillage,
indépendamment aux objets concernés par le lock.

Une autre approche serait d'utiliser des classes Integer
gerant la synchronization telles les SynchronizedVariable de
la librairie de Doug Lea



Soit. Je peux utiliser un java.lang.Integer au lieu de mon
int. Mais ma question portait surtout sur le fait de mettre en
place une synchronisation pour un simple int. Je veux dire un
int (comme tout type primitif) n'est il pas par nature
thread-safe ?


Non. Aucun des types n'est par nature « thread-safe ». Pour la
simple raison que de telles garanties ne sont pas possibles sur
les hardware modernes.

Ce que garantie Java, c'est qu'un accès à int est atomique.
C-à-d que si on modifie un int, un autre thread ne verra jamais
la moitié de la modification. Ou bien il ne voit pas la
modification du tout, ou bien il le voit complète. Mais la
possibilité qu'il ne la voit jamais existe réelement.

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


Avatar
Bruno Jouhier
(snip)
En fait, tu ne synchronises jamais un objet, tu synchronises des
blocs de code. Parfois, il peut être commode d'utiliser un objet
existant ; la plupart du temps, je constate que j'alloue un
objet (de type Object) exprès pour le faire. En fait, ça aurait
été bien plus logique d'avoir un objet d'un type spécial (Lock,
ou Synchronizer, ou ...), et ne pas charger tous les types avec
quelque chose qui ne leur sert pour ainsi dire jamais.


100% d'accord. Les methodes wait() et notify() n'ont rien à faire dans
java.lang.Object. Il faudrait une classe Lock ou une interface Lockable pour
marquer explicitement les objets sur lesquels on va faire de la synchro.

Et aussi, pourquoi ne pas introduire une méthode pour interroger un
"Lockable" et savoir si le thread en cours l'a déjà acquis ou pas. Ca
permettrait, entre autres, d'écrire des assertions sur les locks (vérifier
qu'une méthode est toujours appelée dans le contexte d'un lock donné,
vérifier que les locks multiples sont toujours acquis dans le même ordre,
etc.). Ca serait pas mal aussi de pouvoir énumérer les locks qui ont été
acquis par le thread en cours, par exemple pour vérifier qu'on n'a acquis
qu'un seul lock lorsqu'on fait un wait(). Il y a pas mal de petites choses
comme ça qui pourraient faciliter la programmation multi-thread.

Bruno.

Avatar
James Kanze
Bruno Jouhier wrote:
(snip)


Et aussi, pourquoi ne pas introduire une méthode pour
interroger un "Lockable" et savoir si le thread en cours l'a
déjà acquis ou pas. Ca permettrait, entre autres, d'écrire des
assertions sur les locks (vérifier qu'une méthode est toujours
appelée dans le contexte d'un lock donné, vérifier que les
locks multiples sont toujours acquis dans le même ordre,
etc.). Ca serait pas mal aussi de pouvoir énumérer les locks
qui ont été acquis par le thread en cours, par exemple pour
vérifier qu'on n'a acquis qu'un seul lock lorsqu'on fait un
wait(). Il y a pas mal de petites choses comme ça qui
pourraient faciliter la programmation multi-thread.


Je ne suis pas sûr, mais je crois qu'en général, c'est parce que
les systèmes sous-jacents ne le fournissent pas. En gros, les
threads c'est une partie de Java où ils ont suivi la philosophie
de C de très près, et ils ont fourni ce que fournit le système,
ni plus ni moins. (C'est, par exemple, un des rares endroits en
Java où tu as les comportements indéfinis si fréquents en C et
en C++.)

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Avatar
Bruno Jouhier
"James Kanze" a écrit dans le message de news:
41fd47b4$0$14474$
Bruno Jouhier wrote:
(snip)

Et aussi, pourquoi ne pas introduire une méthode pour
interroger un "Lockable" et savoir si le thread en cours l'a
déjà acquis ou pas. Ca permettrait, entre autres, d'écrire des
assertions sur les locks (vérifier qu'une méthode est toujours
appelée dans le contexte d'un lock donné, vérifier que les
locks multiples sont toujours acquis dans le même ordre,
etc.). Ca serait pas mal aussi de pouvoir énumérer les locks
qui ont été acquis par le thread en cours, par exemple pour
vérifier qu'on n'a acquis qu'un seul lock lorsqu'on fait un
wait(). Il y a pas mal de petites choses comme ça qui
pourraient faciliter la programmation multi-thread.


Je ne suis pas sûr, mais je crois qu'en général, c'est parce que
les systèmes sous-jacents ne le fournissent pas. En gros, les
threads c'est une partie de Java où ils ont suivi la philosophie
de C de très près, et ils ont fourni ce que fournit le système,
ni plus ni moins. (C'est, par exemple, un des rares endroits en
Java où tu as les comportements indéfinis si fréquents en C et
en C++.)


Sans doute. Mais l'info ne doit pas être bien loin car les méthodes notify()
et wait() renvoient une exception lorsqu'on les appelle sans avoir acquis le
lock. J'utilise d'ailleurs ce truc pour implémenter mon système
d'assertions, mais ça serait tellement plus propre et plus efficace si on
avait une API pour ça (on éviterait le coût d'une exception lorsqu'on veut
vérifier qu'un lock n'a pas déjà été pris).

Bruno.


--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34



Avatar
Kupee
bruno conductier wrote:
Si donc tu ne peux utiliser de types primitifs comme argument de ton
bloc synchronized c'est qu'ils ne sont pas des objets.


Ca c'est sur que ce ne sont pas des objets, je crois que Sun l'a
expliqué d'ailleurs par le fait que sans types primitifs le langage
aurait été bien trop lent.