I have a WeakHashMap
of instances implementing an interface (OnPreferenceChangeListener
), and I'm trying to call a method (onPreferenceChanged
) for each instance in the map.
Despite the fact that I've synchronized on the map itself and I don't believe any of the onPreferenceChanged
implementations should be actually changing the map in any way, I'm getting a ConcurrentModificationException
in the forEach
. The code is:
private val listeners = Collections.synchronizedMap(WeakHashMap<OnPreferenceChangeListener, Any>())
fun notifyChanged(property: KProperty<*>) {
val properties = listOf(property.name)
synchronized(listeners) {
listeners.forEach { it.key.onPreferenceChanged(properties) }
}
}
And the stacktrace is:
java.util.ConcurrentModificationException
at java.util.WeakHashMap$HashIterator.nextEntry(WeakHashMap.java:806)
at java.util.WeakHashMap$EntryIterator.next(WeakHashMap.java:845)
at java.util.WeakHashMap$EntryIterator.next(WeakHashMap.java:843)
at my.package.notifyChanged(Preferences.kt:537)
...
If I follow the advice and code snippet in Collections.java
on the javadoc for public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
directly, and use this code:
fun notifyChanged(property: KProperty<*>) {
val properties = listOf(property.name)
val keySet = listeners.keys
synchronized(listeners) {
val iterator = keySet.iterator()
while (iterator.hasNext()) {
iterator.next()
.onPreferenceChanged(properties)
}
}
}
The same thing happens.
If I've synchronized
on the map itself, what else could be modifying it?