在同一方法中修改 ConcurrentHashMap 和 Synchronized ArrayList

发布于 2024-11-26 19:39:13 字数 1162 浏览 2 评论 0原文

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

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

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 不是一个选项,因为会发生大量修改......)此外,如果您知道更好的方法来执行此操作,我们将不胜感激。 ..

I have a collection of objects that is modified by one thread and read by another (more specifically the EDT). I needed a solution that gave me fast look up and also fast indexing (by order inserted), so I'm using a ConcurrentHashMap with an accompanying ArrayList of the keys, so if want to index an entry, I can index the List for the key and then use the returned key to get the value from the hash map. So I have a wrapper class that makes sure when and entry is added, the mapping is added to the hash map and the key is added to the list at the same time, similarly for removal.

I'm posting an example of the code in question:

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();
}

my question is: am I losing all the benefits of using the ConcurrentHashMap (over syncrhonized hashmap) by operating on it in synchronized methods? I have to synchronize the methods to safely modify/read from the ArrayList of keys (CopyOnWriteArrayList is not an option because a lot of modification happens...) Also, if you know of a better way to do this, that would be appreciated...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鱼窥荷 2024-12-03 19:39:13

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

您可以看一下并发链接哈希图的实现,我没有使用过它,所以可以不证明它的功能。

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

我不太确定证明在索引处删除方法的实用性,也许您可​​以提供有关您要解决的问题的更多详细信息?

Yes, using a Concurrent collection and a Synchronized collection in only synchronized blocks is a waste. You wont get the benefits of ConcurrentHashMap because only one thread will be accesing it at a time.

You could have a look at this implementation of a concurrent linked hashmap, I havnt use it so can't attest to it's features.

One thing to consider would be to switching from synchronized blocks to a ReadWriteLock to improve concurrent read only performance.

I'm not really sure of the utility of proving a remove at index method, perhaps you could give some more details about the problem you are trying to solve?

向日葵 2024-12-03 19:39:13

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

It seems that you only care about finding values by index. If so, dump the Map and just use a List. Why do you need the Map?

み零 2024-12-03 19:39:13

不建议按照您的方式混合同步和并发集合。您为什么要维护您感兴趣的内容的两份副本?您可以随时轻松地从地图中获取所有键的列表,而无需维护单独的列表。

Mixing synchronized and concurrent collections the way you have done it is not recommended. Any reason why you are maintaining two copies of the stuff you are interested in? You can easily get a list of all the keys from the map anytime rather than maintaining a separate list.

旧情勿念 2024-12-03 19:39:13

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

因此,对于 getEntry,您只需要查找(在列表中,无论如何应该比地图更快),而对于删除,您不必遍历整个列表。同步化就是这样发生的。

Why not store the values in the list and in the map the key -> index mapping?

so for getEntry you only need on lookup (in the list which should be anyway faster than a map) and for remove you do not have to travers the whole list. Syhnronization happens so.

┾廆蒐ゝ 2024-12-03 19:39:13

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

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

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

You can get all access to the List keys onto the event queue using EventQueue.invokeLater. This will get rid of the synchronization. With all the synching you were not running much in parallel anyway. Also it means the getSize method will give the same answer for the duration of an event.

If you stick with synchronization instead of using invokeLater, at least get the entries hash table out of the synch block. Either way, you get more parallel processing. Of course, entries can now become out-of-synch with keys. The only down side is sometimes a key will come up with a null entry. With such a dynamic table this is unlikely to matter much.

Using the suggestion made by chrisichris to put the values in the list will solve this problem if it is one. In fact, this puts a nice wall between keys and entries; they are now used in completely separate ways. (If your only need for entries is to provide values to the JTable, you can get rid of it.) But entries (if still needed) should reference the entries, not contain an index; maintaining indexes there would be a hopeless task. And always remember that keys and entries are snapshots of "reality" (for lack of a better word) taken at different times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文