对java同步缓存进行批量操作

时间:2016-02-05 12:02:37

标签: java multithreading caching

我想实现一个简单的缓存,它会定期更新,每次更新都会触发一个完整的缓存清除和数据插入。

伪代码:

//context calls periodically this method
cache.clear();
cache.putAll(newValues)

由于其他线程可能在刷新操作期间读取缓存。我需要某种同步。

最简单的解决方案可能类似于以下内容:

computeNewCacheValues()
computeStaleKeys() //e.g. ones are in the cache but are not in the new cache
removeStaleKeysOneByOneFromCache()
updateKeysFromNewCacheValueOneByOne()

实现由ConccurentHashMap实例支持 - 因此在缓存更新期间:

  • 没有发生并发问题(?)
  • 整个过程没有锁定缓存(因此在刷新期间可以访问)

这可能是(?)一个很好的解决方案,但我想知道:还有其他更有效/更安全的方法来实现吗?有没有能够进行此操作的库?

2 个答案:

答案 0 :(得分:2)

如果您总是更换整个缓存,则可以替换它。

final AtomicReference<Map<K, V>> mapRef = new AtomicReference<>();

// assuming you don't modify the map after calling this.
public void update(Map<K, V> map) {
    mapRef.set(map);
}

public V get(K key) {
    // this will always see the latest complete map.
    return mapRef.get().get(key);
}

注意:不需要锁定,因为一旦将Map添加到缓存中,Map就不会被更改。

答案 1 :(得分:0)

供将来参考:

创建“bulk cache”时,最简单的解决方案可能是@Peter提到的解决方案;在一个单独的线程上创建新的缓存,并将旧的缓存的引用更改为新的缓存。

需要考虑的事项:

  • 解决方案有效,因为赋值运算符(“=”)执行是原子的
  • 缓存对象必须为volatile;这样它的值可以被多个线程访问(没有这个线程可能会改变它的值,但是另一个线程将无法看到更改)
  • AtomicReference是另一种选择;基本上它是一个volatile对象的包装器,虽然它增加了一些有用的方法(例如用于审计)