I am using a WeaekHashMap
to implement a Cache. I am wondering if I am iterating over the keys of this map, and at the same time garbage collector is actively removing keys from this map, would I receive a ConcurrentModificationException
?
I do not think so, because as far as I understand, concurrentmodificationexception happens because of bugs in the application code where the developer forgot to understand that the same map is shared/used by other threads and in this case, it should not happen. But wondering how would JVM handle this when WeakHashMap is not synchr开发者_运维知识库onized ?
As bkail said, when GC "removes" an entry from a WeakHashMap
it is not going to cause a concurrent modification. In reality the GC collects the underlying object by there is a hard reference to WeakReference
object (that holds the real key) itself. Therefore, the real object (the reference object) that is directly referenced by the map is not collected so the map does not change until one of your threads calls a method in this map. At that time the map checks the reference queue from the GC and finds all keys that have been collected and removes them from the map - so the actual changes to the map structure occurs on one of your threads.
In thinking of this then there may be one case where you may get a concurrent modification in such a map that you would not get in another kind of map - if you put a key that already exists or call a getter method. But really, in a concurrent application you should be locking around these calls anyway so you would have a really concurrent access bug in your program.
That being said in answer to your question, you really should not use WeakHashMap
for a cache (even if you were talking about caching keys). In a cache you don't want your values 'magically' disappearing when the values are no longer referenced. Typically you want them to disappear when there is a certain maximum number (something like Apache collections LRUMap
) or released on memory demand.
For the later, you can use a map with a SoftReference
(Apache collections provides a ReferenceMap
that allows you to specify the kind of reference for either the key or value). A soft reference is specified to only be released based on memory pressure - a weak reference on the other hand has to do more with GC recognizing that there are no hard reference remaining to the object and can release it at any time. Of course, how a soft reference really works is also dependent on the JVM implementation.
EDIT: I reread your question and want to address one other point. Because the actual modifications occur to the WeakHashMap
internal structures on your own thread, if you only use this map in a single thread you do not need to synchronize any method calls. This behavior is no different than any other Map
.
No, you will not receive ConcurrentModificationException. WeakHashMap uses ReferenceQueue.poll when you call various operations. In other words, each caller is silently responsible for clearing stale entries from the Map. However, that does mean that it is not safe to call methods on a WeakHashMap from multiple threads that would otherwise seem to be "read-only" because any call to get() can destroy the entry linked list that another thread is attempting to iterate.
The WeakHashMap is weak on the keys not the values so it is not appropriate for a cache of values if you want to release space when the value is not being used. You might want to take a look at MapMaker from the google collections.
The documentation is not exactly clear on this but it does say this:
The behavior of the WeakHashMap class depends in part upon the actions of the garbage collector, so several familiar (though not required) Map invariants do not hold for this class. Because the garbage collector may discard keys at any time, a WeakHashMap may behave as though an unknown thread is silently removing entries. In particular, even if you synchronize on a WeakHashMap instance and invoke none of its mutator methods, it is possible for the size method to return smaller values over time, for the isEmpty method to return false and then true, for the containsKey method to return true and later false for a given key, for the get method to return a value for a given key but later return null, for the put method to return null and the remove method to return false for a key that previously appeared to be in the map, and for successive examinations of the key set, the value set, and the entry set to yield successively smaller numbers of elements. - Java API
I think given that description you should expect to occasionally receive ConcurrentModificationException
s while iterating the map. I would design your cache so you do as little iterating as possible.
精彩评论