ConcurrentHashMap与基于ReentrantReadWriteLock的自定义地图重新加载

SiB*_*SiB 9 java locking concurrenthashmap reentrantreadwritelock

Java大师,

目前我们有一个经常HashMap<String,SomeApplicationObject>阅读和偶尔修改的问题,我们遇到的问题是在修改/重新加载期间,Read操作返回null是不可接受的.

要解决这个问题,我有以下选择:

A.使用ConcurrentHashMap

这看起来像是第一选择,但我们所谈论的操作是reload()- 手段clear()紧随其后replaceAll().因此,如果Map是post clear()和pre,replaceAll()则返回null,这是不可取的.即使我synchronize这不解决问题.

B.基于ReentrantReadWriteLock创建另一个实现

在操作Write Lock之前我会在哪里创建获得reload().这似乎更合适,但我觉得必须有一些已经可用的东西,我不需要重新发明轮子.

什么是最好的出路?

编辑任何收藏已经有这样的功能吗?

Pet*_*rey 8

由于您正在重新加载地图,我会在重新加载时替换它.

您可以使用易失性Map执行此操作,在更新时可以完全替换它.


Lou*_*man 5

这听起来很多番石榴的 Cache,但它确实取决于你如何填充地图,以及如何计算值.(披露:我向番石榴捐款.)

真正的问题是,您是否可以指定如何计算SomeApplicationObject给定的输入String.根据你到目前为止告诉我们的内容,它可能看起来像这样......

LoadingCache<String, SomeApplicationObject> cache = CacheBuilder.newBuilder()
   .build(
       new CacheLoader<String, SomeApplicationObject>() {
         public SomeApplicationObject load(String key) throws AnyException {
           return computeSomeApplicationObject(key);
         }
       });
Run Code Online (Sandbox Code Playgroud)

然后,只要您想重建缓存,就可以调用cache.invalidateAll().使用a LoadingCache,您可以调用cache.get(key),如果它还没有计算出值,它将被重新计算.或调用之后,也许cache.invalidateAll(),你可以打电话cache.loadAll(allKeys),但你仍旧需要能够在同一时间,以防有任何疑问进来之间加载单一元素invalidateAllloadAll.

如果这是不可接受的 - 如果你不能单独加载一个值,你必须一次加载它们 - 然后我继续使用Peter Lawrey的方法 - 保持volatile对地图的引用(理想情况下ImmutableMap) ,重新计算整个地图,并在完成后将新地图分配给参考.


ass*_*ias 5

似乎您不确定Peter Lawrey的建议如何实施。它可能看起来像这样:

class YourClass {
    private volatile Map<String, SomeApplicationObject> map;

    //constructors etc.

    public void reload() {
        Map<String,SomeApplicationObject> newMap = getNewValues();
        map = Collections.unmodifiableMap(newMap);
    }
}
Run Code Online (Sandbox Code Playgroud)

没有并发问题,因为:

  • 新地图是通过局部变量创建的,根据定义,该局部变量不会共享- getNewValues不需要同步或原子
  • 分配给map原子
  • map 是易失的,保证其他线程可以看到更改