2

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

我发布了一个有问题的代码示例:

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(通过同步哈希图)的所有好处?我必须同步方法以安全地从键的 ArrayList 修改/读取(CopyOnWriteArrayList 不是一个选项,因为会发生很多修改......)另外,如果您知道更好的方法来做到这一点,那将不胜感激。 ..

4

5 回答 5

0

是的,仅在同步块中使用并发集合和同步集合是一种浪费。您不会获得 ConcurrentHashMap 的好处,因为一次只有一个线程会访问它。

你可以看看这个并发链接 hashmap的实现,我没有使用它,所以无法证明它的功能。

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

我不太确定在 index 方法中证明 remove 的效用,也许您可​​以提供有关您要解决的问题的更多详细信息?

于 2011-07-28T14:26:09.220 回答
0

您似乎只关心按索引查找值。如果是这样,转储地图并仅使用列表。为什么需要地图?

于 2011-07-28T14:28:23.480 回答
0

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

于 2011-07-28T14:31:28.850 回答
0

为什么不将值存储在列表和映射中的键 -> 索引映射?

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

于 2011-07-28T14:34:03.657 回答
0

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

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

使用 chrisichris 提出的建议将值放入列表中将解决此问题,如果它是一个。事实上,这在keys和之间设置了一堵漂亮的墙entries;它们现在以完全不同的方式使用。(如果您只需要为entriesJTable 提供值,则可以摆脱它。)但是entries(如果仍然需要)应该引用条目,而不是包含索引;维护索引将是一项无望的任务。永远记住这一点,keys并且entries是在不同时间拍摄的“现实”(因为没有更好的词)的快照。

于 2011-07-28T17:09:22.707 回答