java ConcurrentHashMap 是否需要包装在同步块中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25998536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does a ConcurrentHashMap need to be wrapped in a synchronized block?
提问by MeanwhileInHell
Do all non-retreival operations on a ConcurrentHashMap (put()
, remove()
etc.) need to be wrapped in a synchronized(this)
block? 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()
.
这样做,即ConcurrentHashMap(所有非retreival操作put()
,remove()
等)需要在被包裹synchronized(this)
块?我知道所有这些操作都是线程安全的,那么这样做有什么真正的好处/需要吗?使用的唯一操作是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);
}
...
}
回答by sparc_spread
No, you are losing the benefits of ConcurrentHashMap
by doing that. 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.)
不,你正在失去ConcurrentHashMap
这样做的好处。您也可以使用HashMap
withsynchronized
或synchronizedMap()
来锁定整个表(这是您在将操作包装在 中时所做的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. 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 Practiceby Goetz et al).
目的ConcurrentHashMap
是通过允许对表进行并发读/写而不锁定整个表来增加并发代码的吞吐量。该表通过使用锁条带(多个锁而不是一个,每个锁分配给一组哈希桶 - 请参阅Goetz 等人的Java 并发实践)在内部支持这一点。
Once you are using ConcurrentHashMap
, all standard map methods (put()
, remove()
, etc.) become atomic by virtue of the lock striping etc. in the implementation. 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.
一旦您使用了ConcurrentHashMap
,所有标准的映射方法(put()
、remove()
等) 都会由于实现中的锁条带等而变成原子的。唯一的权衡是方法喜欢size()
并且isEmpty()
可能不一定返回准确的结果,因为它们的唯一方法是所有操作都锁定整个表。
The ConcurrentMap
interfaceinterface 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 (e.g. 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()
同时接受key和value(删除仅当其值等于你传递参数的条目),等等。这些操作过去需要锁定整个表,因为它们需要两个方法调用才能完成(例如,如果您使用标准实现,则putIfAbsent()
需要同时调用containsKey()
and put()
,包装在一个synchronized
块中Map
。)再一次,使用这些方法可以获得更大的吞吐量,通过避免锁定整个表。
回答by kapex
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. Put and get operations are blocking, so all other threads have to wait and can't access the map concurrently. The ConcurrentHashMap
- as the name suggest - allows concurrent access on the other hand. You lose this benefit if you add synchronization.
ConcurrentHashMap
创建的原因是同步映射(在问题中手动实现或以通常的方式实例化Collections.synchronizedMap(map)
)在被许多线程访问时表现出糟糕的性能。Put 和 get 操作是阻塞的,所以所有其他线程都必须等待并且不能同时访问映射。本ConcurrentHashMap
-正如其名字暗示-允许在另一方面并发访问。如果添加同步,您将失去此优势。