我正在使用LinkedHashMap,并且环境是多线程的,因此这个结构需要是线程安全的。在特定事件期间,我需要读取整个地图推送到数据库并清除所有。
大部分时间只会写入此地图。此地图限制了50个条目。
我使用的是Oracle MAF,它没有Collections.syncronizedMap。那么,我需要在同步块中放置什么东西以确保写入和读取不会让我遇到concurrentModificationException等
几个要求:
答案 0 :(得分:3)
那么,我需要在同步块中放置什么东西以确保写入和读取不会遇到我的concurrentModificationException等
所有方法调用都应该在同步块中。
棘手的是使用迭代器,因为你必须在迭代器的生命周期中持有锁。 e.g。
// pre Java 5.0 code
synchronized(map) { // the lock has to be held for the whole loop.
for(Iterator iter = map.entrySet().iterator(); iter.hashNext(); ) {
Map.Entry entry = iter.next();
String key = (String) entry.getKey();
MyType value = (MyType) entry.getValue();
// do something with key and value.
}
}
答案 1 :(得分:1)
在多线程环境中,大多数LinkedHashMap
操作都需要synchronization
,即使看起来像get(key)
一样纯粹的操作,get(key)
实际上也会改变某些内部节点。最简单的方法是使用Collections.synchronizedMap
。
Map<K,V> map = Collections.synchronizedMap(new LinkedHashMap<>());
现在,如果它不可用,您可以轻松添加它,因为它只是一个简单的decorator
周围地图synchronize
所有操作。
class SyncMap<T,U> implements Map<T,U>{
SyncMap<T,U>(LinkedHashMap<T,U> map){
..
}
public synchronized U get(T t){
..
}
}
答案 2 :(得分:0)
如果您使用的是java版本1.5或更高版本,则可以使用java.util.concurrent.ConcurrentHashMap
。
这是在多线程环境中使用的Map的最有效实现。
它还添加了一些像putIfAbsent
这样的方法,对地图上的原子操作非常有用。
来自java doc:
检索操作(包括get)一般不阻止,所以可能 与更新操作重叠(包括put和remove)。检索 反映最近完成的更新操作的结果 坚持他们的发作。 适用于汇总操作,例如putAll和 明确,并发检索可能反映了 的插入或删除 一些条目
因此,验证这是您对班级的期望。
如果您的地图只有50条记录,需要用作循环队列,为什么要使用地图?使用其中一个Queue实现不是更好吗?
如果您需要使用LinkedHashMap,请使用以下命令:
Map m = Collections.synchronizedMap(new LinkedHashMap());
来自LinkedHashMap
的{{3}}:
请注意,此实现未同步。如果有多个线程 同时访问链接的哈希映射,以及至少一个线程 从结构上修改地图,必须在外部进行同步。 这通常通过同步某个对象来完成 自然地封装了地图。如果不存在此类对象,则为地图 应该&#34;包裹&#34;使用Collections.synchronizedMap方法。这个 最好在创建时完成,以防止意外的不同步 访问地图:
Map m = Collections.synchronizedMap(new LinkedHashMap(...));