以相同的方法修改ConcurrentHashMap和Synchronized ArrayList

时间:2011-07-28 14:18:54

标签: java synchronized concurrenthashmap

我有一组对象,这些对象由一个线程修改并由另一个线程读取(更具体地说是EDT)。我需要一个解决方案,让我快速查找并快速索引(通过插入顺序),所以我使用ConcurrentHashMap与附带的ArrayList的键,所以如果要索引一个条目,我可以索引List为键然后使用返回的键从哈希映射中获取值。所以我有一个包装器类,它确保添加时间和条目,映射被添加到哈希映射中,并且密钥同时添加到列表中,类似于删除。

我发布了相关代码的示例:

private List<K> keys = Collections.synchronizedList(new ArrayList<K>(INITIAL_CAPACITY));

private ConcurrentMap<K, T> entries = new ConcurrentHashMap<K, T>(INITIAL_CAPACITY, .75f);

public synchronized T getEntryAt(int index){
     return entries.get(keys.get(index));
}

**public synchronized void addOrReplaceEntry(K key, T value){
     T result = entries.get(key);
     if(result == null){
         entries.putIfAbsent(key, value);
         keys.add(key);
     }
     else{
         entries.replace(key, result);
     }
}**

public syncrhonized T removeEntry(K key, T value){
     keys.remove(key);
     entries.remove(key, value);
}

public synchronized int getSize(){
     return keys.size();
}

我的问题是:我是否通过在同步方法中对它进行操作而失去了使用ConcurrentHashMap(over syncrhonized hashmap)的所有好处?我必须同步方法来安全地修改/读取键的ArrayList(CopyOnWriteArrayList不是一个选项,因为发生了很多修改...)另外,如果你知道更好的方法来做到这一点,那将是值得赞赏的。 ..

5 个答案:

答案 0 :(得分:0)

是的,仅在同步块中使用Concurrent集合和Synchronized集合是一种浪费。您不会从ConcurrentHashMap中获益,因为一次只有一个线程可以访问它。

你可以看看concurrent linked hashmap的这个实现,我一直在使用它,所以无法证明它的功能。

要考虑的一件事是从同步块切换到ReadWriteLock以提高并发只读性能。

我不太确定在索引方法中证明删除的效用,也许你可以提供一些关于你试图解决的问题的更多细节?

答案 1 :(得分:0)

您似乎只关心通过索引查找值。如果是这样,请转储Map并使用List。你为什么需要地图?

答案 2 :(得分:0)

不建议按照您的方式混合synchronized和并发集合。你为什么要保留两份你感兴趣的东西?您可以随时轻松地从地图中获取所有键的列表,而不是维护单独的列表。

答案 3 :(得分:0)

为什么不将值存储在列表和地图中的键 - &gt;索引映射?

所以对于getEntry你只需要查找(在列表中应该比地图更快)并且对于删除你不必遍历整个列表。 Syhnronization恰好发生了。

答案 4 :(得分:0)

您可以使用keys将所有对列表EventQueue.invokeLater的访问权限置于事件队列中。这将摆脱同步。通过所有同步,您无论如何都没有并行运行。此外,它意味着getSize方法将在事件持续时间内给出相同的答案。

如果您坚持使用同步而不是使用invokeLater,那么至少从同步块中获取entries哈希表。无论哪种方式,您都可以获得更多并行处理。当然,entries现在可能与keys失去同步。唯一的缺点是有时一个密钥会出现一个空条目。有了这样一个动态表,这不太重要。

使用chrisichris提出的建议将值放在列表中将解决这个问题,如果它是一个。事实上,这会在keysentries之间留下一道漂亮的墙;它们现在以完全不同的方式使用。 (如果你只需要entries来为JTable提供值,你就可以摆脱它。)但是entries(如果仍然需要的话)应该引用条目,不包含索引;保持索引将是一个无望的任务。并且永远记住,keysentries是在不同时间拍摄的“现实”(缺少更好的词)的快照。