简体   繁体   English

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

[英]modifying a ConcurrentHashMap and Synchronized ArrayList in same method

I have a collection of objects that is modified by one thread and read by another (more specifically the EDT). 我有一个由一个线程修改并由另一个线程(更具体地说是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. 我需要一个可以快速查找和快速索引(按插入顺序)的解决方案,因此我正在使用ConcurrentHashMap及其键的ArrayList,因此,如果要为条目建立索引,我可以为List编制索引键,然后使用返回的键从哈希映射中获取值。 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? 我的问题是:通过在同步方法中对其进行操作,我是否会失去使用ConcurrentHashMap的所有好处? 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... 我必须同步方法以安全地修改/从键的ArrayList中读取(CopyOnWriteArrayList不是一种选择,因为会发生很多修改...)而且,如果您知道一种更好的方法,将不胜感激。 ..

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. 您不会获得ConcurrentHashMap的好处,因为一次只能有一个线程访问它。

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. 要考虑的一件事是从同步块切换到ReadWriteLock,以提高并发只读性能。

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

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? 为什么需要地图?

Mixing synchronized and concurrent collections the way you have done it is not recommended. 不建议按照您的方式混合synchronized和并发的集合。 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. 您可以随时轻松地从地图中获取所有键的列表,而无需维护单独的列表。

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. 因此,对于getEntry,您只需要进行查找(在列表中,无论如何它都应该比地图更快),而对于remove,则不必遍历整个列表。 Syhnronization happens so. 同步化就是这样发生的。

You can get all access to the List keys onto the event queue using EventQueue.invokeLater . 您可以使用EventQueue.invokeLater将对事件keys列表的所有访问权限都授予事件队列。 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. 这也意味着getSize方法将在事件持续时间内给出相同的答案。

If you stick with synchronization instead of using invokeLater , at least get the entries hash table out of the synch block. 如果您坚持使用同步而不是使用invokeLater ,则至少invokeLater synch块中获取entries哈希表。 Either way, you get more parallel processing. 无论哪种方式,您都会获得更多的并行处理。 Of course, entries can now become out-of-synch with keys . 当然, entries现在可以与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. 使用chrisichris提出的建议将值放在列表中将解决此问题(如果为一)。 In fact, this puts a nice wall between keys and entries ; 实际上,这在keysentries之间架起了一道漂亮的墙; 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; (如果您唯一需要entries就是向JTable提供值,则可以删除它。)但是, entries (如果仍然需要)应该引用条目,而不包含索引; 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. 始终记住, keysentries是在不同时间拍摄的“真实”(缺少更好的单词)的快照。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM