java有一个“LinkedConcurrentHashMap”数据结构吗?
我需要一个LinkedHashMap的数据结构,并且是线程安全的。
我怎样才能做到这一点 ?
您可以将地图封装在Collections.synchronizedMap中以获取用于维护广告订单的同步散列表。 这不像ConcurrentHashMap那么高效(并且没有实现ConcurrentMap的额外的接口方法),但是它确实为你带来(有点)线程安全的行为。
即使是强大的Google集合似乎也没有解决这个特殊问题。 但是,有一个项目试图解决这个问题。
我在同步上说了一些话,因为在并发修改exception可能发生的意义上,迭代仍然不是线程安全的。
这个问题有很多不同的方法。 你可以使用:
Collections.synchronizedMap(new LinkedHashMap());
正如其他答复所build议的,但这有几个问题需要注意。 最值得注意的是,当迭代集合时,您经常需要保持集合同步locking,这反过来会阻止其他线程访问集合,直到完成迭代为止。 ( 请参阅Java理论和实践:并发集合类 )。 例如:
synchronized(map) { for (Object obj: map) { // Do work here } }
运用
new ConcurrentHashMap();
可能是一个更好的select,因为你不需要locking集合来迭代它。
最后,您可能需要考虑更多function的编程方法。 那就是你可以认为地图本质上是不可改变的。 您可以创build一个包含旧地图内容和新添加内容的新地图,而不是添加到现有地图。 这听起来很奇怪,但实际上是Scala处理并发和收集的方式
在Google代码下有一个实现 。 来自他们网站的引用:
用作软件caching的高性能版本的java.util.LinkedHashMap。
devise
- 并发链表通过ConcurrentHashMap运行,以提供驱逐顺序。
- 支持插入和访问有序的驱逐策略(FIFO,LRU和Second Chance)。
您可以使用仅适用于Java SE / EE 6或更高版本的ConcurrentSkipListMap。 这是订购presevering中,按键sorting根据其自然顺序。 你需要有一个比较器或者让键比较对象。 为了模仿一个链接哈希映射行为(迭代顺序是添加条目的时间顺序),我实现了我的关键对象,总是比给定的其他对象大,除非它是相等的(无论对于你的对象)。 一个包装的同步链接哈希映射是不够的,因为正如http://www.ibm.com/developerworks/java/library/j-jtp07233.html中所述; :“同步集合包装,synchronizedMap和synchronizedList,有时被称为条件线程-safe – 所有单独的操作都是线程安全的,但是控制stream程依赖于前面操作结果的操作序列可能会受到数据竞争的影响清单1中的第一个片段显示了普通的put-if-absent方法 – – 如果一个条目在Map中不存在,那么不幸的是,正如所写的,另一个线程可能在containsKey()方法返回的时间和put()方法之间插入一个具有相同键值的值,方法被调用,如果你想确保一次插入,你需要用一个同步的块来包装这对语句,这个同步块在Map m上同步。
所以只有ConcurrentSkipListMap比正常的ConcurrentHashMap慢3-5倍。
Collections.synchronizedMap(new LinkedHashMap())
由于ConcurrentHashMap提供了一些不在Map接口中的重要的额外方法,简单地用LinkedMap包装一个LinkedHashMap不会给你相同的function,特别是它们不会给你任何像putIfAbsent(),replace (key,oldValue,newValue)和remove(key,oldValue)方法,使得ConcurrentHashMap非常有用。
除非有一些已经实现了你想要的apache库,否则你可能不得不使用LinkedHashMap并提供合适的同步块。
我只是尝试基于插入顺序LinkedConcurrentHashMap同步有界LRU映射; 与读/写locking同步。 所以当你使用迭代器时, 您必须获取WriteLock以避免ConcurrentModificationException。
这比Collections.synchronizedMap.
public class LinkedConcurrentHashMap<K, V> { private LinkedHashMap<K, V> linkedHashMap = null; private final int cacheSize; private ReadWriteLock readWriteLock = null; public LinkedConcurrentHashMap(LinkedHashMap<K, V> psCacheMap, int size) { this.linkedHashMap = psCacheMap; cacheSize = size; readWriteLock=new ReentrantReadWriteLock(); } public void put(K key, V value) throws SQLException{ Lock writeLock=readWriteLock.writeLock(); try{ writeLock.lock(); if(linkedHashMap.size() >= cacheSize && cacheSize > 0){ K oldAgedKey = linkedHashMap.keySet().iterator().next(); remove(oldAgedKey); } linkedHashMap.put(key, value); }finally{ writeLock.unlock(); } } public V get(K key){ Lock readLock=readWriteLock.readLock(); try{ readLock.lock(); return linkedHashMap.get(key); }finally{ readLock.unlock(); } } public boolean containsKey(K key){ Lock readLock=readWriteLock.readLock(); try{ readLock.lock(); return linkedHashMap.containsKey(key); }finally{ readLock.unlock(); } } public V remove(K key){ Lock writeLock=readWriteLock.writeLock(); try{ writeLock.lock(); return linkedHashMap.remove(key); }finally{ writeLock.unlock(); } } public ReadWriteLock getLock(){ return readWriteLock; } public Set<Map.Entry<K, V>> entrySet(){ return linkedHashMap.entrySet(); } }
答案几乎不是,没有任何等同于已sorting的ConcurrentHashMap(如LinkedHashMap)。 正如其他人指出的,你可以使用Collections.synchronizedMap(-yourmap-)包装你的集合,但是这不会给你同样的细粒度locking级别。 它会在每个操作中阻止整个地图。
你最好的select是在任何访问地图时使用同步(当然,你可能不关心脏读),或者在地图上编写一个封装来确定它应该或不应该locking的时间。