并发LRU缓存实现

use*_*011 6 java multithreading

我需要线程安全且高效的LRU缓存实现代码.下面的代码不是线程安全的.是否可以使用增强此代码ConcurrentHashMap.提前致谢.

private class LruCache<A, B> extends LinkedHashMap<A, B> {
    private final int maxEntries;

    public LruCache(final int maxEntries) {
        super(maxEntries + 1, 1.0f, true);
        this.maxEntries = maxEntries;
    }

    @Override
    protected boolean removeEldestEntry(final Map.Entry<A, B> eldest) {
        return super.size() > maxEntries;
    }
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*tto 6

您可以做的最好的事情就是使其具有线程安全性,即Collections.synchronizedMap(map)按照javadoc中的说明进行包装:

请注意,此实现未同步。如果多个线程同时访问链接的哈希映射,并且至少有一个线程在结构上修改该映射,则必须在外部进行同步。通常,通过在自然封装地图的某个对象上进行同步来实现。如果不存在这样的对象,则应使用Collections.synchronizedMap方法“包装”地图。最好在创建时完成此操作,以防止意外不同步地访问地图:

Map m = Collections.synchronizedMap(new LinkedHashMap(...));
Run Code Online (Sandbox Code Playgroud)

但是,仅使其完全线程安全还不够,您仍然需要使用包装后的地图实例作为对象的监视器来保护地图内容上的任何迭代:

Map m = Collections.synchronizedMap(map);
...
Set s = m.keySet();  // Needn't be in synchronized block
...
synchronized (m) {  // Synchronizing on m, not s!
    Iterator i = s.iterator(); // Must be in synchronized block
    while (i.hasNext())
      foo(i.next());
}
Run Code Online (Sandbox Code Playgroud)

使用我们开箱即用的功能,这几乎是您可以轻松完成的所有事情JDK,如果您想要线程安全和更高效的功能,则应该CacheGoogle Guava看一下。

这是LRU最大大小为的2内置缓存的示例guava

ConcurrentMap<String, String> cache = 
    CacheBuilder.newBuilder()
        .maximumSize(2L)
        .<String, String>build().asMap();
cache.put("a", "b");
cache.put("b", "c");
System.out.println(cache);
cache.put("a", "d");
System.out.println(cache);
cache.put("c", "d");
System.out.println(cache);
Run Code Online (Sandbox Code Playgroud)

输出:

{b=c, a=b}
{b=c, a=d}
{c=d, a=d}
Run Code Online (Sandbox Code Playgroud)


Ali*_*aka 5

找到 Guava 的缓存。我自己没用过。

Cache 与 ConcurrentMap 类似,但又不完全相同。

来源: https: //github.com/google/guava/wiki/CachesExplained

例子:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
       .expireAfterAccess(10, TimeUnit.MINUTES)
       .maximumSize(1000)
       .build(
           new CacheLoader<Key, Graph>() {
             public Graph load(Key key) { // no checked exception
               return createExpensiveGraph(key);
             }
           });

...
return graphs.getUnchecked(key);
Run Code Online (Sandbox Code Playgroud)