SoftReferenceでキャッシュ

キャッシュを自作するときは、SoftReferenceを使うのが定番らしい。

public class SimpleCache<K, V> {

    private ConcurrentHashMap<K, SoftReference<V>> map = new ConcurrentHashMap<K, SoftReference<V>>();
    
    public V get(K key) {
        SoftReference<V> ref = this.map.get(key);
        if (ref == null) {
            return null;
        }
        V value = ref.get();
        if (value == null) {
            this.map.remove(key);
            return null;
        }
        return value;
    }
    
    public void put(K key, V value) {
        SoftReference<V> oldReference = this.map.put(key, new SoftReference<V>(value));
        if (oldReference != null) {
            oldReference.clear();
            //oldReference.enqueue();
        }
    }
}

こんな感じ?

しかし、これではGCでキャッシュは消えても、キーが使用されない限り、そのキーにマップされているキャッシュを参照していたSoftReferenceインスタンスが消えずに残ってしまう…。サーバアプリで使うなら適当なタイミングでマップの掃除をさせないとダメか。

いっそ、

public class SimpleCache<K, V> {
    private SoftReference<ConcurrentHashMap<K, V>> softRef;

    // ...
}

というのもアリかもしれない。

そういえばJSR 107というキャッシュAPIの仕様があるらしいのだが、実装はGoogle App Engineで使っているもの以外に無いのだろうか?