concurrenthashmap与基于reentrantreadwritelock的用于重新加载的自定义Map

6tr1vspr  于 2021-07-09  发布在  Java
关注(0)|答案(3)|浏览(315)

java 大师,
目前我们有一个 HashMap<String,SomeApplicationObject> 它经常被读取,偶尔会被修改,在修改/重新加载过程中,读取操作会返回一些问题 null 这是不可接受的。
要解决此问题,我有以下选项:
答。使用concurrenthashmap
这看起来像是第一选择,但我们所说的手术是 reload() -手段 clear() 然后 replaceAll() . 所以如果 Map 正在阅读文章 clear() 以及 replaceAll() 它返回null,这是不需要的。即使我 synchronize 这并不能解决问题。
b。基于reentrantreadwritelock创建另一个实现
在那里我会创造 Write Lock 之前 reload() 操作。这似乎更合适,但我觉得必须有一些已经可以为这个,我不需要重新发明车轮。
最好的出路是什么?
编辑是否已有具有此功能的集合可用?

a0x5cqrl

a0x5cqrl1#

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

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

    //constructors etc.

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

不存在并发问题,因为:
新Map是通过局部变量创建的,根据定义,局部变量不是共享的- getNewValues 不需要同步或原子
转让给 map 是原子的 map 是可变的,这保证了其他线程将看到更改

ldxq2e6h

ldxq2e6h2#

既然你正在重新加载Map,我会在重新加载时替换它。
您可以通过使用volatileMap来实现这一点,当更新它时,您可以完全替换它。

omjgkv6w

omjgkv6w3#

这听起来很像Guava Cache ,尽管这实际上取决于如何填充Map,以及如何计算值(披露:我为Guava捐款。)
真正的问题是您是否可以指定如何计算 SomeApplicationObject 给定输入 String . 根据你目前告诉我们的,可能是这样的。。。

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

然后,每当你想重建缓存,你只要调用 cache.invalidateAll() . 用一个 LoadingCache ,然后你可以打电话 cache.get(key) 如果它还没有计算出这个值,它将被重新计算。或者在打过电话之后 cache.invalidateAll() ,您可以拨打 cache.loadAll(allKeys) ,但是您仍然需要能够一次加载单个元素,以防在两个元素之间出现任何查询 invalidateAll 以及 loadAll .
如果这是不可接受的--如果你不能单独加载一个值,你必须一次加载所有的值--那么我将继续使用peter lawrey的方法--保持 volatile 对Map的引用(理想情况下是 ImmutableMap ),重新计算整个Map,并在完成后将新Map分配给引用。

相关问题