Java 分块阅读ConcurrentHashMap(或类似内容)
我有一个程序,它有一个Java 分块阅读ConcurrentHashMap(或类似内容),java,concurrency,hashmap,java.util.concurrent,Java,Concurrency,Hashmap,Java.util.concurrent,我有一个程序,它有一个ConcurrentHashMap,不同的线程可以在该映射中添加/删除项目 我很想知道什么是阅读25个项目的地图的最佳方法。 我想做的是这样的:用户点击一个按钮,然后从地图上读取25个项目(无论顺序如何)。之后,他可以点击“下一步”按钮,阅读另外25项内容(与前25项不同),以此类推 我不确定是否可以使用ConcurrentHashMap来实现这一点。我不想使用数据库,我想把它保存在内存中。 我不认为将Map转换为ArrayList会有帮助,因为大多数情况下项目都是从Map
ConcurrentHashMap
,不同的线程可以在该映射中添加/删除项目
我很想知道什么是阅读25个项目的地图的最佳方法。
我想做的是这样的:用户点击一个按钮,然后从地图上读取25个项目(无论顺序如何)。之后,他可以点击“下一步”按钮,阅读另外25项内容(与前25项不同),以此类推
我不确定是否可以使用ConcurrentHashMap
来实现这一点。我不想使用数据库,我想把它保存在内存中。
我不认为将Map
转换为ArrayList
会有帮助,因为大多数情况下项目都是从Map中添加/删除的
我对任何解决方案都持开放态度,即使是第三方库
更新:我也没有绑定到ConcurrentHashMap
。我只是在寻找最好的解决办法
更新2:它们是String
感谢您,因为字符串键是严格排序的,所以这是一种方法
- 它是和,并且经常可以用来代替ConcurrentHashMap
/获取
/放置
与删除
一样快O(log N)
- 作为奖励,您将免费获得自然遍历顺序
tailMap
,然后从结果子映射构造迭代器或流:
return map.tailMap(lastKey, false).entrySet()
.stream()
.limit(pageSize)
.collect(Collectors.toList());
请注意,tailMap
即使从地图中删除了定位键,也会成功。迭代将从比锚点大的下一个关键点开始
如果键的顺序不严格,或者需要O(1)复杂度,那么您可能更喜欢另一种建议—按单元索引顺序遍历的开放寻址哈希表。然而,在标准Java类中没有这样的实现。这种映射的线程安全通常是通过锁定实现的。< P>如果您不想使用CONRUSTHASHMAP,那么可以考虑使用Link KeHasMMAP,并同步它。 linkedhashmap按插入顺序存储,因此您可以对其进行迭代。 但是,您需要保留一个lastViewedElement,当它被删除时,用一个新的有效值更新它,以便您可以从那里进行迭代 它应该正确同步(可能是手动同步),因为它不是线程安全的。粗略的实现是:
(我是通过head而不是IDE来完成这项工作的,所以它可能会遗漏一些东西。而且我的泛型没有达到标准,而且您可能根本不需要泛型…)
公共类MyMagicMap实现映射
私有LinkedHashMap innerMap=新LinkedHashMap();
X lastKey=null;
@凌驾
公共作废认沽权(X键,Y值){
已同步(MyMagicMap.class){
if(innerMap.contains(键)){
删除(键);
}
innerMap.put(键、值);
}
}
@凌驾
公共Y删除(X键){
已同步(MyMagicMap.class){
if(key.equals)(lastKey){
lastKey=getKeyBefore(lastKey);
}
返回innerMap.remove(键);
}
}
私有X getKeyBefore(X oldLastKey){
Iterator it=innerMap.KeySet.Iterator();
for(X键:it){
if(key.equals(oldLastKey)){
返回它。下一步();
}
}
}
公共地图getNextBatch(整数计数){
已同步(MyMagicMap.class){
Map resultMap=new HashMap();
迭代器it=innerMap.keySet().Iterator();
X lastKey=扫描FORLASTKEY(it);
if(lastKey==null){
返回结果图;
}
resultMap.put(lastKey),innerMap.get(key);
for(int i;i
需要注意的是,在相关块上有线程同步,只有一个线程应该执行此操作。还请注意,delete方法的性能很差(O(N))
如果你想做得更快,你必须实现你自己的LinkedHashMap,它允许你有效地确定下一行。听起来很难,直到你意识到你只需要一个HashMap>,三元组的键值是previous和next。再次同步put和remove操作,这是为了保持li的完整性圣,即
void put(X key, Y value) {
// synchronize this
Triplet<X,Y,X> lastValueInMap = innerMap.get(endOfMapKey);
lastValueInMap.rightElement = key;
innerMap.put(X, new Triplet(endOfMapKey, value, null);
endOfMapKey = key;
}
Y remove(X key) {
// synchronize this.
Triplet<X,Y,X> valueTriplet = innerMap.remove(key);
if(valueTriplet.left != null)
if(valueTriplet.right != null) {
innerMap.get(valueTriplet.left).right = valueTriplet.right;
innerMap.get(valueTriplet.right).left=valueTriplet.left;
} else
// etc.
}
}
void put(X键,Y值){
//同步这个
三元组lastValueInMap=innerMap.get(endOfMapKey);
lastValueInMap.rightElement=键;
put(X,新的三元组(endOfMapKey,value,null);
endOfMapKey=key;
}
Y移除(X键){
//同步这个。
三元组值三元组=innerMap.remove(键);
if(valueTriplet.left!=null)
if(valueTriplet.right!=null){
get(valueTriplet.left).right=valueTriplet.right;
get(valueTriplet.right).left=valueTriplet.left;
}否则
//等等。
}
}
最后要注意的是put方法,它显式地删除已经存在的键,而不是更新值。由于LinkedHashMap的更新不会修改插入顺序,这意味着如果不删除,任何已经在批中读取并随后更新的键K将永远不会显示在ne中
void put(X key, Y value) {
// synchronize this
Triplet<X,Y,X> lastValueInMap = innerMap.get(endOfMapKey);
lastValueInMap.rightElement = key;
innerMap.put(X, new Triplet(endOfMapKey, value, null);
endOfMapKey = key;
}
Y remove(X key) {
// synchronize this.
Triplet<X,Y,X> valueTriplet = innerMap.remove(key);
if(valueTriplet.left != null)
if(valueTriplet.right != null) {
innerMap.get(valueTriplet.left).right = valueTriplet.right;
innerMap.get(valueTriplet.right).left=valueTriplet.left;
} else
// etc.
}
}