Reputation: 1131
I'm reading the Java Doc about the WeakHashMap and I get the basic concept. Because of the GC thread(s) acting in the background, you can get 'unusual behavior', such as a ConcurrentModificationException when iterating and etc.
The thing I don't get is that if the default implementation is not synchronized and does not contain lock in any way, then how come there is no possibility of getting an inconsistent state. Say you have 2 threads. A GC thread deleting some key at a certain index and at same time and at the same index, a user thread is inserting in the array a key value pair.
To me, if there is no synchronization, then there is a high risk of getting a hash map that is inconsistent.
Even worse, doing something like this might actually be super dangerous because v might actually be null.
if (map.contains(k)) {
V v = map.get(k)
}
Am I missing something?
Upvotes: 3
Views: 1914
Reputation: 145
This class is intended primarily for use with key objects whose equals methods test for object identity using the == operator. Once such a key is discarded it can never be recreated, so it is impossible to do a lookup of that key in a WeakHashMap at some later time and be surprised that its entry has been removed.
So if one uses WeakHashMap
for objects whose equals()
is based on identity check, all is fine. The first case you mentioned ("A GC thread deleting some key at a certain index and at same time and at the same index, a user thread is inserting in the array a key value pair.") is impossible because as long as the user thread keeps a reference to the key object it cannot be discarded by GC.
And the same stands for the second example:
if (map.contains(k)) {
V v = map.get(k)
}
You keep reference k
so the corresponding object is reachable and cannot be discarded.
But
This class will work perfectly well with key objects whose equals methods are not based upon object identity, such as String instances. With such recreatable key objects, however, the automatic removal of WeakHashMap entries whose keys have been discarded may prove to be confusing.
Upvotes: 0
Reputation: 280993
The inconsistent state issues you mention do not arise because the GC does not actively restructure WeakHashMaps. When the garbage collector frees the referent of a weak reference, the corresponding entry is not physically removed from the map; the entry merely becomes stale, with no key. At some later point, the entry may be physically removed during some other operation on the map, but the GC won't take on that responsibility.
You can see one Java version's implementation of this design on grepcode.
Upvotes: 5
Reputation: 2276
Referring to
even if you synchronize on a WeakHashMap [...] it is possible for the size method to return smaller values over time
the javadoc sufficiently explains to me that there is a possibility for an inconsistent state and that it is completely independent from synchronization.
A few examples later, the given example is referred to, too:
for the containsKey method to return true and later false for a given key
So basically, one should never rely on the state of a WeakHashMap
. but use it as atomic as possible. The given example should therefore be rephrased to
V v = map.get(k);
if(null != v) {
}
or
Optional.ofNullable(map.get(k)).ifPresent(() -> { } );
Upvotes: 0
Reputation: 50716
What you're describing is what the documentation explicitly states:
Because the garbage collector may discard keys at any time, a
WeakHashMap
may behave as though an unknown thread is silently removing entries.
The only mistake you're making is the assumption that you can protect the state by synchronizing. That doesn't work because the synchronization would not be mutual on the part of the GC. To quote the documentation:
In particular, even if you synchronize on a
WeakHashMap
instance and invoke none of its mutator methods, it is possible for thesize
method to return smaller values over time, for theisEmpty
method to returnfalse
and thentrue
, for thecontainsKey
method to returntrue
and laterfalse
for a given key, for theget
method to return a value for a given key but later returnnull
, for theput
method to returnnull
and theremove
method to returnfalse
for a key that previously appeared to be in the map, and for successive examinations of the key set, the value collection, and the entry set to yield successively smaller numbers of elements.
Upvotes: 0