简体   繁体   English

是否需要将ConcurrentHashMap包装在同步块中?

[英]Does a ConcurrentHashMap need to be wrapped in a synchronized block?

Do all non-retreival operations on a ConcurrentHashMap ( put() , remove() etc.) need to be wrapped in a synchronized(this) block? 对ConcurrentHashMap( put()remove()等)的所有非retreival操作是否需要包装在synchronized(this)块中? I understand that all of these operations are thread-safe, so is there any real benefit/need in doing so? 我知道所有这些操作都是线程安全的,所以这样做有什么好处/需要吗? The only operations used are put() and remove() . 使用的唯一操作是put()remove()

protected final Map<String, String> mapDataStore = new ConcurrentHashMap<String, String>();

public void updateDataStore(final String key, final String value) {
    ...
    synchronized (this) {
        mapDataStore.put(key, value);
    }
    ...
}

No, you are losing the benefits of ConcurrentHashMap by doing that. 不,你这样做会失去ConcurrentHashMap的好处。 You may as well be using a HashMap with synchronized or synchronizedMap() to lock the whole table (which is what you do when wrapping operations in synchronized , since the monitor implied is the entire object instance.) 您也可以使用带有synchronizedsynchronizedMap()HashMap来锁定整个表(这是您在synchronized包装操作时所执行的操作,因为监视器隐含的是整个对象实例。)

The purpose of ConcurrentHashMap is to increase the throughput of your concurrent code by allowing concurrent read/writes on the table without locking the entire table. ConcurrentHashMap的目的是通过允许对表进行并发读/写而不锁定整个表来增加并发代码的吞吐量。 The table supports this internally by using lock striping (multiple locks instead of one, with each lock assigned to a set of hash buckets - see Java Concurrency in Practice by Goetz et al). 该表通过使用锁定条带内部支持这一点(多个锁而不是一个,每个锁分配给一组散列桶 - 参见Goetz等人的Java Concurrency in Practice )。

Once you are using ConcurrentHashMap , all standard map methods ( put() , remove() , etc.) become atomic by virtue of the lock striping etc. in the implementation. 一旦你使用ConcurrentHashMap ,所有标准的map方法( put()remove()等)都会因为实现中的锁条带等而变为原子。 The only tradeoffs are that methods like size() and isEmpty() may not necessarily return accurate results, since the only way they could would be for all operations to lock the whole table. 唯一的权衡是像size()isEmpty()这样的方法可能不一定会返回准确的结果,因为它们可能是所有操作锁定整个表的唯一方法。

The ConcurrentMap interface interface also adds new atomic compound operations like putIfAbsent() (put something only if it the key is not already in the map), remove() accepting both key and value (remove an entry only if its value equals a parameter you pass), etc. These operations used to require locking the whole table because they needed two method calls to accomplish (eg putIfAbsent() would need calls to both containsKey() and put() , wrapped inside one synchronized block, if you were using a standard Map implementation.) Once again, you gain greater throughput using these methods, by avoiding locking the entire table. ConcurrentMap接口接口还添加了新的原子复合操作,如putIfAbsent() (仅当键不在映射中时才放置东西), remove()接受键和值(仅当条目的值等于参数时才删除条目)这些操作过去需要锁定整个表,因为它们需要两个方法调用才能完成(例如putIfAbsent()需要调用containsKey()put() ,包含在一个synchronized块中,如果你使用的话标准的Map实现。)再一次,通过避免锁定整个表,您可以使用这些方法获得更大的吞吐量。

Synchronizing those operations has no benefit here - it actually degrades performance if you don't need synchronization. 同步这些操作在这里没有任何好处 - 如果您不需要同步,它实际上会降低性能。

The reason ConcurrentHashMap was created, is that synchronized maps (either implemented by hand like in the question or instantiated in the usual way with Collections.synchronizedMap(map) ) show bad performance when accessed by many threads. 创建ConcurrentHashMap的原因是同步映射(在问题中手动实现或者以通常的方式使用Collections.synchronizedMap(map)实例化)在许多线程访问时显示不良性能。 Put and get operations are blocking, so all other threads have to wait and can't access the map concurrently. Put和get操作是阻塞的,因此所有其他线程必须等待并且不能同时访问映射。 The ConcurrentHashMap - as the name suggest - allows concurrent access on the other hand. ConcurrentHashMap - 顾名思义 - 允许并发访问。 You lose this benefit if you add synchronization. 如果添加同步,则会失去此优势。

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

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