I'm creating a memoization cache with the following characteristics:

  • a cache miss will result in computing and storing an entry
    • this computation is very expensive
    • this computation is idempotent
  • unbounded (entries never removed) since:
    • the inputs would result in at most 500 entries
    • each stored entry is very small
    • cache is relatively shorted-lived (typically less than an hour)
    • overall, memory usage isn't an issue
  • there will be thousands of reads - over the cache's lifetime, I expect 99.9%+ cache hits
  • must be thread-safe

What would have superior performance, or under what conditions would one solution be favored over the other?

ThreadLocal HashMap:

class MyCache {
    private static class LocalMyCache {
        final Map<K,V> map = new HashMap<K,V>();

        V get(K key) {
            V val = map.get(key);
            if (val == null) {
                val = computeVal(key);
                map.put(key, val);
            }
            return val;
        }
    }

    private final ThreadLocal<LocalMyCache> localCaches = new ThreadLocal<LocalMyCache>() {
        protected LocalMyCache initialValue() {
            return new LocalMyCache();
        }
    };

    public V get(K key) {
        return localCaches.get().get(key);
    }
}

ConcurrentHashMap:

class MyCache {
    private final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<K,V>();

    public V get(K key) {
        V val = map.get(key);
        if (val == null) {
            val = computeVal(key);
            map.put(key, val);
        }
        return val;
    }
}

I figure the ThreadLocal solution would initially be slower if there a lot of threads because of all the cache misses per thread, but over thousands of reads, the amortized cost would be lower

Edit
Report