How to effectively use a String as a WeakHashMap key in Java, or an alternative solution
Asked Answered
V

1

9

I am managing a project in Java that stores user data. Users can be online, or offline. When users are online, their data is loaded into the data object for easy accessibility, and offloaded when they log off.

However, for offline users, in the interests of preventing data loss from concurrent access of data from multiple commands manipulating the data at the same time, I store a weakhashmap as a cache of the loaded user data objects. Should anything need to access an offline data object to modify it, the system will check the cache first before loading it from file.

The only thing that I can think of how to store them is by a string key, which represents the users username. But because of how java works, that does not always seem to work due to the VM's string caching system.

Originally I thought of using a string wrapper, but again because of how hashmaps work (by use of hashcode), creating a new string wrapper would not get me the value i need, and if i stored the string wrappers, that would defeat the purpose by storing a strong reference to the key at all times (preventing the removal of the key from the weakhashmap).

Maybe I'm just not understanding how the weakhashmap is supposed to be used :S If this isn't how the weakhashmap is supposed to be used, I'm open to accept other ideas of how to do what I wish.

Vesicant answered 13/4, 2014 at 3:53 Comment(2)
Can you describe specifically what problem you're having with using String values as keys?Latrena
Well, to be honest, the results are never predictable. I have two maps in play here, a standard hashmap that stores the data objects that are for online users, and the weakhashmap for cached users. Sometimes it will refuse to remove it even though there are no references (strong reference to the hashmap is removed upon user logging out), and sometimes it will remove it while there is a strong reference in the main hashmap while the user is online. Results are extremely unpredictable :\Vesicant
L
13

The reason it behaves unpredictably is explained in the Javadoc for WeakHashMap in the last sentence of this paragraph:

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. 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.

What you really want is a map where the entries are removed when the values get garbage collected, rather than when the keys get garbage collected - that is, for which the values are weak, rather than for which the keys are weak. You can find help on that issue at this question:

Java Weak Hash Map - Need to remove entry based on weakness of value, not key

Latrena answered 13/4, 2014 at 4:17 Comment(2)
Thank you, fine sir :] The guava solution worked like an absolute charm! Best part is, the overarching API I was working against already provided guava as part of the toolset!Vesicant
I would agree with the "perfectly well with" part of this doc, only if Java maps allowed you to replace the object being used for the key. Since you can only update its value, it doesn't work well in many cases, even when you account for the discarded entries. For example, a deduplicating object cache of WeakHashMap<T,WeakReference<T>> can't be implemented easily because the key can become mismatched from the object stored in the value when the value needs updating because the WeakReference has been discarded, but the entry in the map hasn't yet.Legged

© 2022 - 2024 — McMap. All rights reserved.