提问者:小点点

并发HashMap与基于ReentantReadWriteLock的自定义重新加载映射


Java古鲁,

目前我们有一个HashMap

要解决此问题,我有以下选项:

A.使用并发哈希图

这看起来像是第一个选择,但我们正在谈论的操作是重新加载()-意味着lear()后跟replace eAll()。因此,如果在lear()和prereplace eAll()之后读取Map,它会返回null,这是不可取的。即使我同步这并不能解决问题。

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

在那里我将在重新加载()操作之前创建获取写锁。这似乎更合适,但我觉得必须有一些可用的东西,我不需要重新发明轮子。

最好的出路是什么?

编辑是否已经有任何具有此类功能的收藏?


共3个答案

匿名用户

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

您可以通过使用易失性映射来做到这一点,您可以在更新时将其完全替换。

匿名用户

你似乎不确定彼得·劳里的建议如何实施。它可能是这样的:

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

    //constructors etc.

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

没有并发问题,因为:

  • 新映射是通过局部变量创建的,根据定义,局部变量是不共享的-getNewValue不需要同步或原子
  • map的赋值是原子的
  • map是易失性的,这保证了其他线程会看到变化

匿名用户

这听起来很像Guava的Cache,尽管它实际上取决于您如何填充地图以及如何计算值。(披露:我为Guava做出了贡献。)

真正的问题是,您是否可以在给定输入String的情况下指定如何计算您的有应用对象。根据您到目前为止告诉我们的内容,它可能看起来像这样……

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

然后,每当您想重建缓存时,您只需调用cache. validateAll()。使用LoadingCache,您可以调用cache.get(key),如果它还没有计算值,它将重新计算。或者在调用cache.validateAll()之后,您可以调用cache.loadAll(allKeys),尽管您仍然需要能够一次加载单个元素,以防validateAllloadAll之间出现任何查询。

如果这是不可接受的——如果您不能单独加载一个值,您必须一次加载所有值——那么我将继续使用Peter Lawrey的方法——保留对映射的易失性引用(理想情况下是ImmutableMap),重新计算整个映射,并在完成后将新映射分配给引用。