Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ConcurrentHashMap与基于ReentrantReadWriteLock的用于重新加载的自定义映射_Java_Locking_Concurrenthashmap_Reentrantreadwritelock - Fatal编程技术网

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()
和pre
replaceAll()
读取
Map
,它将返回null,这是不可取的。即使I
synchronize
也无法解决问题

B.根据

在这里,我将在
reload()操作之前创建acquire
Write 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中预加载,并一直从映射中读取。。。有时系统管理员可以重新加载这些值。