Дата публикации: 04.11.2013 9:08:44
Sometimes, Java programmers need to implement a simple caching functionality, and the first idea that comes to their mind is to try the WeakHashMap class. However, using this type of Map as a cache is a bad idea for several reasons. The first reason is that this class uses the weak references as the underlying memory management mechanism. The second reason is that the weak references are used only for the keys but not for the values. Finally, some tasks require a reference-equality mechanism instead of object-equality to compare keys or values.
According to the WeakReference specification, weak references are the most often used to implement canonicalizing mapping. So the SoftReference class is preferable, because its specification says that soft references are the most often used to implement memory-sensitive caches. However, in some cases, it is possible to use weak references. For example, the Introspector class caches BeanInfo instances by using the WeakHashMap class. In this case, Class instances are used as keys and they have strong references from the class loader that loaded them. So, this cache behaves as a normal map, which entries will be deleted from it automatically, when the class loader is no longer in use.
Refrain for coping the existing implementation from the WeakHashMap class and replacing all occurrences of the WeakReference class with the SoftReference class. This is another bad idea, since strong references are used to store values. So, the value that can use a lot of memory will not be collected until a strong reference to the key exists. As a temporary solution, you can use SoftReference or WeakReference to wrap the values. However, when the garbage collector collects the value, the corresponding entry will remain the same.
So, an universal cache is supposed to use all the types of references, including weak, soft, and strong. Depending a specific case, you will select a particular type for the keys as well as for the values. I am going to create such a cache and describe it in a series of articles.
In the first article I would like to talk about the class hierarchy that is created to store references to the keys and values.
Consider the Ref interface that declares the following methods:
interface Ref { Object getOwner(); T getReferent(); boolean isStale(); }
The getOwner method returns an object that contains the target reference. It is needed because a cache entry must contain two references: one for the key, another - for the value. Both references are not strong, so you cannot use the WeakHashMap approach, which entry extends the WeakReference class. The getReferent method returns the object to refer. If this object is collected, the method returns null. However, null does not necessarily mean that the object is collected, because a valid key or value can be null as well. To check whether the object was collected or not, use the isStale method.
The StrongRef class is implemented as read-only JavaBean. The first two properties are set in the constructor and the stale property always returns false. Two other implementations are pretty similar, except for their base classes. The SoftRef class extends the SoftReference class, whereas the WeakRef class extends the WeakReference class. To create an instance of one of these classes you should use not only the owner and the referent but also the reference queue to register the created references. In these cases, the getReferent method returns the result of the get method from superclass. The isStale method returns true, if this result is null. That's why these classes cannot be used to store null.
The Kind enumeration declares three types of references, each of which has a method to create a reference of a certain type. Note that if the referred object is null, then the create method for any type will return the StrongRef instance.
PS. The StrongRef, SoftRef, and WeakRef classes must be created only by using the create method, so it is possible to move them into the Kind enumeration as a private static inner classes.
PPS. Related article and analogues: MapMaker and ReferenceMap.