安全访问多线程HashMap Java
我有一个应用程序,它有一个ConcurrentHashMap,在本地存储存储在外部服务器上的数据副本。地图每隔几秒钟更新一次数据的新副本 我有一个循环,每隔几秒钟运行一次,它可以访问HashMap,并按照值的顺序将元素添加到数组中(它实际上做的更多,但这并不重要)。我的问题是,如果数据在创建数组的过程中发生变化,那么你可以在不同的地方有重复的键,或者留下一些完全的。 例如:安全访问多线程HashMap Java,java,multithreading,Java,Multithreading,我有一个应用程序,它有一个ConcurrentHashMap,在本地存储存储在外部服务器上的数据副本。地图每隔几秒钟更新一次数据的新副本 我有一个循环,每隔几秒钟运行一次,它可以访问HashMap,并按照值的顺序将元素添加到数组中(它实际上做的更多,但这并不重要)。我的问题是,如果数据在创建数组的过程中发生变化,那么你可以在不同的地方有重复的键,或者留下一些完全的。 例如: // Map starts out like this 1 -> value1 2 -> value2 3 -
// Map starts out like this
1 -> value1
2 -> value2
3 -> value3
4 -> value4
// First 2 elements of array created
value1,value2
// Map is updated
3 -> value3
1 -> value1
2 -> value2
4 -> value4
// Last 2 elements of array created
value1,value2,value1,value4
如您所见,如果映射没有更改,则数组将是:“value1、value2、value3、value4”或“value2、value3、value1、value4”,如果它是在更新后运行的
下面是一些示例代码,它不是原始代码,但应该可以解释我的问题:
Map<Integer, String> mapThatGetsUpdated = new ConcurrentHashMap<Integer, String>();
String[] array = new String[mapThatGetsUpdated.size()];
for (int i = 0; i < mapThatGetsUpdated.size(); i++) {
array[i] = mapThatGetsUpdated.get(i);
}
Map-mapThatGetsUpdated=new-ConcurrentHashMap();
String[]数组=新字符串[mapThatGetsUpdated.size()];
对于(int i=0;i
这样做的明显方法是复制映射,然后在使用后丢弃它,但我希望使用另一种方法,因为映射可能非常大,并且可能必须每秒复制几次。这是一个问题,因为尽管
ConcurrentHashMap
是线程安全的,但您在执行复合操作时没有锁定
如果要保证状态一致,必须防止阅读时写入。
如果您希望读卡器在整个读操作中看到相同的信息,则必须:
- 或者在读取期间阻止写入
- 创建开始时正在读取的实体的快照
synchronized
锁定映射
,允许一次打开一个
这是许多新手程序员的第一次求助。它将有效地消除使用ConcurrentHashMap
的任何好处
选项2(不要这样做)
在读取地图之前,复制地图
注意到迭代可能只是在做一些循环以外的事情,您可以尝试通过在synchronized
块中复制映射并使用副本来最小化读取时的锁定
因为你经常阅读,这很可能也没有帮助
选项3
使用原子参考
。将读取器中的引用复制到本地引用。编写器将引用替换为全新的映射
此选项的可行性取决于正在进行的写作量。它被调用,如果写操作少而读操作多,则可以获得良好的吞吐量
它不需要显式锁定,但需要编写者做更多的工作
选项4
使用一个。将Map
更改为HashMap
并自己控制并发性(编写一个包装类)
使用ReadLock
锁定读取,使用WriteLock
锁定写入。你可以有很多读者,但一次只能有一个作者
将保证读取的一致性。在更新或读取hashmap时,您能锁定(同步)hashmap吗?hashmap不保持插入顺序。@Braj编辑了这篇文章,使其更加清晰,我正在使用数组中索引的键。@immibis我认为这可能会破坏
ConcurrentHashMap
的作用吗?