4

Is there softreference-based LinkedHashMap in Java? If no, has anyone got a snippet of code that I can probably reuse? I promise to reference it correctly.

Thanks.

His
  • 5,891
  • 15
  • 61
  • 82
  • 4
    If you're planning to do this for a memory-sensitive cache, be aware that available memory is a very bad way to regulate anything. In a large-heap environment, you can keep stale objects for a very long time, which slows down overall operation. Time and size-based caches are far better. You may also be interested in this: http://www.kdgregory.com/index.php?page=java.refobj – kdgregory May 14 '09 at 11:07

3 Answers3

6

WeakHashMap doesn't preserve the insertion order. It thus cannot be considered as a direct replacement for LinkedHashMap. Moreover, the map entry is only released when the key is no longer reachable. Which may not be what you are looking for.

If what you are looking for is a memory-friendly cache, here is a naive implementation you could use.

package be.citobi.oneshot;

import java.lang.ref.SoftReference;
import java.util.LinkedHashMap;

public class SoftLinkedCache<K, V>
{
    private static final long serialVersionUID = -4585400640420886743L;

    private final LinkedHashMap<K, SoftReference<V>> map;

    public SoftLinkedCache(final int cacheSize)
    {
        if (cacheSize < 1)
            throw new IllegalArgumentException("cache size must be greater than 0");

        map = new LinkedHashMap<K, SoftReference<V>>()
        {
            private static final long serialVersionUID = 5857390063785416719L;

            @Override
            protected boolean removeEldestEntry(java.util.Map.Entry<K, SoftReference<V>> eldest)
            {
                return size() > cacheSize;
            }
        };
    }

    public synchronized V put(K key, V value)
    {
        SoftReference<V> previousValueReference = map.put(key, new SoftReference<V>(value));
        return previousValueReference != null ? previousValueReference.get() : null;
    }

    public synchronized V get(K key)
    {
        SoftReference<V> valueReference = map.get(key);
        return valueReference != null ? valueReference.get() : null;
    }
}
frroland
  • 199
  • 1
  • 4
3

The best idea I've seen for this is wrapping LinkedHashMap so that everything you put into it is a WeakReference.

UPDATE: Just browsed the source of WeakHashMap and the way it handles making everything a WeakReference while still playing nice with generics is solid. Here's the core class signature it uses:

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>

I suggest browsing the source more in depth for other implementation ideas.

UPDATE 2: kdgregory raises a good point in his comment - all my suggestion does is make sure the references in the Map won't keep the referent from being garbage-collected. You still need to clean out the dead references manually.

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • 4
    This doesn't quite work, because the references will never disappear, they'll just get cleared. And you'll end up with a map full of dead references. If you look closer at the WeakHashMap code, you'll see that it lazily purges the dead references (I believe using a reference queue). – kdgregory May 14 '09 at 11:05
2

have a look at this post. It shows how to implement a SoftHashMap...

pgras
  • 12,614
  • 4
  • 38
  • 46
  • 2
    Apache Shiro already has an implementation of this method (with approval) and licensed it under Apache v2. It's packaged with Apache [Shiro][1]. You can find the documentation [here][2] and the source code [here][3]. [1]: http://en.wikipedia.org/wiki/Apache_Shiro [2]: http://shiro.apache.org/static/1.1.0/apidocs/ [3]: http://shiro.apache.org/static/1.1.0/apidocs/src-html/org/apache/shiro/util/SoftHashMap.html – DallinDyer Oct 05 '11 at 15:23