Java ConcurrentHashMap与基于ReentrantReadWriteLock的用于重新加载的自定义映射
爪哇大师 目前,我们有一个Java ConcurrentHashMap与基于ReentrantReadWriteLock的用于重新加载的自定义映射,java,locking,concurrenthashmap,reentrantreadwritelock,Java,Locking,Concurrenthashmap,Reentrantreadwritelock,爪哇大师 目前,我们有一个HashMap,它被频繁地读取,偶尔被修改,并且在修改/重新加载过程中,read操作返回null,这是不可接受的 要解决此问题,我有以下选项: A.使用 这看起来像是第一个选择,但我们正在讨论的操作是reload()-意思是clear(),后面是replaceAll()。因此,如果在clear()和prereplaceAll()读取Map,它将返回null,这是不可取的。即使Isynchronize也无法解决问题 B.根据 在这里,我将在reload()操作之前创建ac
HashMap
,它被频繁地读取,偶尔被修改,并且在修改/重新加载过程中,read操作返回null
,这是不可接受的
要解决此问题,我有以下选项:
A.使用
这看起来像是第一个选择,但我们正在讨论的操作是reload()
-意思是clear()
,后面是replaceAll()
。因此,如果在clear()
和prereplaceAll()
读取Map
,它将返回null,这是不可取的。即使Isynchronize
也无法解决问题
B.根据
在这里,我将在reload()操作之前创建acquireWrite Lock
。这似乎更合适,但我觉得必须有一些东西已经可以用于此,我不需要重新发明车轮
最好的出路是什么
编辑是否已有具有此功能的收藏?由于您正在重新加载地图,我将在重新加载时替换它
您可以通过使用volatile映射来实现这一点,在更新映射时将其完全替换。这听起来很像,但实际上取决于如何填充映射以及如何计算值。(披露:我为番石榴捐款。)
真正的问题是,如果输入字符串
,是否可以指定如何计算SomeApplicationObject
。就根据你到目前为止告诉我们的,它可能看起来像这样
LoadingCache<String, SomeApplicationObject> cache = CacheBuilder.newBuilder()
.build(
new CacheLoader<String, SomeApplicationObject>() {
public SomeApplicationObject load(String key) throws AnyException {
return computeSomeApplicationObject(key);
}
});
LoadingCache cache=CacheBuilder.newBuilder()
.建造(
新缓存加载程序(){
公共SomeApplicationObject加载(字符串键)引发任何异常{
返回computeSomeApplicationObject(键);
}
});
然后,每当您想要重建缓存时,只需调用cache.invalidateAll()
。使用LoadingCache
,然后可以调用cache.get(key)
,如果尚未计算该值,则会重新计算该值。或者在调用cache.invalidateAll()
之后,您可以调用cache.loadAll(allKeys)
,尽管您仍然需要能够一次加载单个元素,以防在invalidateAll
和loadAll
之间出现任何查询
如果这是不可接受的——如果你不能单独加载一个值,你必须一次加载所有值——那么我将继续使用Peter Lawrey的方法——保留对映射的volatile
引用(理想情况下是ImmutableMap
),重新计算整个映射,并在完成后将新映射分配给引用。您似乎不确定如何实现Peter Lawrey的建议。它可能是这样的:
class YourClass {
private volatile Map<String, SomeApplicationObject> map;
//constructors etc.
public void reload() {
Map<String,SomeApplicationObject> newMap = getNewValues();
map = Collections.unmodifiableMap(newMap);
}
}
classyourclass{
私有易失性映射;
//施工人员等。
公共空间重新加载(){
Map newMap=getNewValues();
map=Collections.unmodifiableMap(newMap);
}
}
不存在并发问题,因为:
- 新映射是通过局部变量创建的,根据定义,局部变量不是共享的-
getNewValues
不需要同步或原子化
map
的赋值是原子的
map
是易变的,这保证了其他线程将看到更改
您的地图实际上是不可变的,这使它们成为通过volatile
发布的完美目标。实际上是不可变的对不起,我不太理解不可变的
。。。你能提供一些提示吗???你能详细解释一下吗?不知何故,我很难解释为什么这会奏效。我确实理解volatile将保证可见性,但是像clear-than-replaceAll这样的复合操作将如何工作呢?谢谢。要替换整个映射,只需在构建新副本时将新映射分配给字段中的旧volatile引用即可。i、 你真的是在替换全部,甚至是映射本身,而不仅仅是它的内容。SomeApplicationObject是一个实体,当应用程序启动时从DB中预加载,并一直从映射中读取。。。有时系统管理员可以重新加载这些值。