Salut j'ai un problème avec le synchronizedSet retourné par Collections
: je fais ceci
J'ai 2 threads capables de retirer des éléments dedans.
L'un fait directement un
set.remove(Object)
l'autre utilise un iterator et retire sous condition :
l'iterator est bien dans un bloc synchronisé comme ils le disent dans la
javadoc synchronisé sur le set lui même :
synchronized (set) {
Iterator it = set.iterator();
while (it.hasNext())
MyObject o = (MyObject) it.next();
if (o.done()) it.remove();
}
Et bien sur ca marche pas ca lance des
java.util.ConcurrentModificationException car si moi je synchronise sur
le set comme ils le disent, toute la synchronisation interne est faite
sur un mutex champ de la classe. Alors c'est bien beau
de synchroniser mais si on synchronise pas sur la même chose ben ca
risque pas de marcher ...
Alors que faire ?
Ces wrappers synchronisés sont-ils completements cons ou j'ai manqué un
truc dans leur utilisation ?
merci
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Stephane Zuckerman
synchronized (set) { Iterator it = set.iterator(); while (it.hasNext()) MyObject o = (MyObject) it.next(); if (o.done()) it.remove(); ^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y retires des éléments, ce qui risque de la rend incohérente. En pratique, nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer sur une collection et modifier la structure de celle-ci (comprendre : modifier son nombre d'éléments, en en supprimant ou en rajoutant).
-- "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce que je veux !" "The obvious mathematical breakthrough would be development of an easy way to factor large prime numbers." (Bill Gates, The Road Ahead)
synchronized (set) {
Iterator it = set.iterator();
while (it.hasNext())
MyObject o = (MyObject) it.next();
if (o.done()) it.remove();
^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y
retires des éléments, ce qui risque de la rend incohérente. En pratique,
nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne
peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer
sur une collection et modifier la structure de celle-ci (comprendre :
modifier son nombre d'éléments, en en supprimant ou en rajoutant).
--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)
synchronized (set) { Iterator it = set.iterator(); while (it.hasNext()) MyObject o = (MyObject) it.next(); if (o.done()) it.remove(); ^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y retires des éléments, ce qui risque de la rend incohérente. En pratique, nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer sur une collection et modifier la structure de celle-ci (comprendre : modifier son nombre d'éléments, en en supprimant ou en rajoutant).
-- "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce que je veux !" "The obvious mathematical breakthrough would be development of an easy way to factor large prime numbers." (Bill Gates, The Road Ahead)
Kupee
Stephane Zuckerman wrote:
synchronized (set) { Iterator it = set.iterator(); while (it.hasNext()) MyObject o = (MyObject) it.next(); if (o.done()) it.remove();
^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y retires des éléments, ce qui risque de la rend incohérente. En pratique, nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer sur une collection et modifier la structure de celle-ci (comprendre : modifier son nombre d'éléments, en en supprimant ou en rajoutant).
Je pensais que la méthode remove de l'iterator était justement faite pour pouvoir retirer un élément de la collection pendant l'itération, ce qui semble etre ce que dit la javadoc de cette méthode
"Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method."
D'ailleurs a quoi peut bien servir de synchroniser le block sur l'objet "set" puique pendant ce temps les méthodes remove et add du set sont synchronisées sur autre chose. Ca n'empeche donc en aucun cas un autre thread de venir modifier le Set durant l'itération non ?
Stephane Zuckerman wrote:
synchronized (set) {
Iterator it = set.iterator();
while (it.hasNext())
MyObject o = (MyObject) it.next();
if (o.done()) it.remove();
^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y
retires des éléments, ce qui risque de la rend incohérente. En pratique,
nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne
peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer
sur une collection et modifier la structure de celle-ci (comprendre :
modifier son nombre d'éléments, en en supprimant ou en rajoutant).
Je pensais que la méthode remove de l'iterator était justement faite
pour pouvoir retirer un élément de la collection pendant l'itération, ce
qui semble etre ce que dit la javadoc de cette méthode
"Removes from the underlying collection the last element returned by the
iterator (optional operation). This method can be called only once per
call to next. The behavior of an iterator is unspecified if the
underlying collection is modified while the iteration is in progress in
any way other than by calling this method."
D'ailleurs a quoi peut bien servir de synchroniser le block sur l'objet
"set" puique pendant ce temps les méthodes remove et add du set sont
synchronisées sur autre chose. Ca n'empeche donc en aucun cas un autre
thread de venir modifier le Set durant l'itération non ?
synchronized (set) { Iterator it = set.iterator(); while (it.hasNext()) MyObject o = (MyObject) it.next(); if (o.done()) it.remove();
^^^^^^^^^^
}
Ton problème se trouve là, non ? Tu itères sur une liste, mais tu y retires des éléments, ce qui risque de la rend incohérente. En pratique, nous sommes d'accord, ça ne devrait pas poser problème, mais le code ne peut savoir à quel moment tu fais ta suppression.
C'est marqué dans la doc si je ne me trompe pas : il ne faut pas itérer sur une collection et modifier la structure de celle-ci (comprendre : modifier son nombre d'éléments, en en supprimant ou en rajoutant).
Je pensais que la méthode remove de l'iterator était justement faite pour pouvoir retirer un élément de la collection pendant l'itération, ce qui semble etre ce que dit la javadoc de cette méthode
"Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method."
D'ailleurs a quoi peut bien servir de synchroniser le block sur l'objet "set" puique pendant ce temps les méthodes remove et add du set sont synchronisées sur autre chose. Ca n'empeche donc en aucun cas un autre thread de venir modifier le Set durant l'itération non ?
Stephane Zuckerman
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
-- "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce que je veux !" "The obvious mathematical breakthrough would be development of an easy way to factor large prime numbers." (Bill Gates, The Road Ahead)
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet());
c.add("toto"); c.add("tata"); c.add("tutu");
for (Iterator i = c.iterator(); i.hasNext();) {
String s = (String) i.next();
c.remove(s);
}
me génère une belle exception :
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782)
at java.util.HashMap$KeyIterator.next(HashMap.java:818)
at net.beuarh.lasher.Main.testIterator(Main.java:97)
at net.beuarh.lasher.Main.main(Main.java:155)
Exception in thread "main"
--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
-- "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce que je veux !" "The obvious mathematical breakthrough would be development of an easy way to factor large prime numbers." (Bill Gates, The Road Ahead)
Kupee
Stephane Zuckerman wrote:
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments de la Collections avec la méthode remove de l'itérator. Le problème est que le javadoc de synchronizedCollection dit qu'en cas d'utilisation d'un iterator on doit synchroniser sur la collection elle même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en aucun cas d'utiliser le remove ou le add de la collection puisque ces méthodes ne sont pas synchronisées sur this. Donc en conclusion ces collections sont a moitié synchronisées puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Stephane Zuckerman wrote:
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet());
c.add("toto"); c.add("tata"); c.add("tutu");
for (Iterator i = c.iterator(); i.hasNext();) {
String s = (String) i.next();
c.remove(s);
}
me génère une belle exception :
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782)
at java.util.HashMap$KeyIterator.next(HashMap.java:818)
at net.beuarh.lasher.Main.testIterator(Main.java:97)
at net.beuarh.lasher.Main.main(Main.java:155)
Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments
de la Collections avec la méthode remove de l'itérator.
Le problème est que le javadoc de synchronizedCollection dit qu'en cas
d'utilisation d'un iterator on doit synchroniser sur la collection elle
même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en
aucun cas d'utiliser le remove ou le add de la collection puisque ces
méthodes ne sont pas synchronisées sur this.
Donc en conclusion ces collections sont a moitié synchronisées
puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments de la Collections avec la méthode remove de l'itérator. Le problème est que le javadoc de synchronizedCollection dit qu'en cas d'utilisation d'un iterator on doit synchroniser sur la collection elle même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en aucun cas d'utiliser le remove ou le add de la collection puisque ces méthodes ne sont pas synchronisées sur this. Donc en conclusion ces collections sont a moitié synchronisées puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Kupee
Kupee wrote:
Stephane Zuckerman wrote:
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments de la Collections avec la méthode remove de l'itérator. Le problème est que le javadoc de synchronizedCollection dit qu'en cas d'utilisation d'un iterator on doit synchroniser sur la collection elle même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en aucun cas d'utiliser le remove ou le add de la collection puisque ces méthodes ne sont pas synchronisées sur this. Donc en conclusion ces collections sont a moitié synchronisées puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Pardon j'ai faux : le mutex utilisé est bien le set lui même, l'erreur vient bien de moi, la méthode utilisée sur mon objet durant l'itération faisait elle même un remove tout simplement. Mon dev est un peu tortueux :)
Kupee wrote:
Stephane Zuckerman wrote:
En tout cas, le code suivant :
Collection c = Collections.synchronizedCollection(new HashSet());
c.add("toto"); c.add("tata"); c.add("tutu");
for (Iterator i = c.iterator(); i.hasNext();) {
String s = (String) i.next();
c.remove(s);
}
me génère une belle exception :
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782)
at java.util.HashMap$KeyIterator.next(HashMap.java:818)
at net.beuarh.lasher.Main.testIterator(Main.java:97)
at net.beuarh.lasher.Main.main(Main.java:155)
Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments
de la Collections avec la méthode remove de l'itérator.
Le problème est que le javadoc de synchronizedCollection dit qu'en cas
d'utilisation d'un iterator on doit synchroniser sur la collection elle
même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en
aucun cas d'utiliser le remove ou le add de la collection puisque ces
méthodes ne sont pas synchronisées sur this.
Donc en conclusion ces collections sont a moitié synchronisées
puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Pardon j'ai faux : le mutex utilisé est bien le set lui même, l'erreur
vient bien de moi, la méthode utilisée sur mon objet durant l'itération
faisait elle même un remove tout simplement. Mon dev est un peu tortueux :)
Collection c = Collections.synchronizedCollection(new HashSet()); c.add("toto"); c.add("tata"); c.add("tutu"); for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); c.remove(s); }
me génère une belle exception :
java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$KeyIterator.next(HashMap.java:818) at net.beuarh.lasher.Main.testIterator(Main.java:97) at net.beuarh.lasher.Main.main(Main.java:155) Exception in thread "main"
Oui parce que lorsqu'on utilise un iterator il faut retirer les éléments de la Collections avec la méthode remove de l'itérator. Le problème est que le javadoc de synchronizedCollection dit qu'en cas d'utilisation d'un iterator on doit synchroniser sur la collection elle même. Ce qui empeche effectivement d'avoir 2 iterators mais n'empeche en aucun cas d'utiliser le remove ou le add de la collection puisque ces méthodes ne sont pas synchronisées sur this. Donc en conclusion ces collections sont a moitié synchronisées puisqu'elles ne permettent pas d'utiliser un iterator de manière fiable.
Pardon j'ai faux : le mutex utilisé est bien le set lui même, l'erreur vient bien de moi, la méthode utilisée sur mon objet durant l'itération faisait elle même un remove tout simplement. Mon dev est un peu tortueux :)