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

Mea*_*ell 31 java synchronized concurrenthashmap

这样做,即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);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

spa*_*ead 53

不,你正在失去ConcurrentHashMap这样做的好处.您也可以使用HashMapwith synchronized或synchronizedMap()锁定整个表(这是您在执行包装操作时所执行的操作synchronized,因为监视器隐含的是整个对象实例.)

目的ConcurrentHashMap是通过允许在表上进行并发读/写而不锁定整个表来增加并发代码的吞吐量.该表通过使用锁定条带内部支持这一点(多个锁而不是一个,每个锁分配给一组散列桶 - 参见Goetz等人的Java Concurrency in Practice).

一旦使用ConcurrentHashMap,所有标准映射方法(put(),remove()等)都会因实现中的锁定条带等而变为原子.唯一的权衡是方法喜欢size()并且isEmpty()可能不一定返回准确的结果,因为它们可能是所有操作锁定整个表的唯一方法.

该ConcurrentMap接口界面还增加了如新原子复合操作putIfAbsent()(把东西只有当它的关键是不是已经在地图),remove()同时接受key和value(删除仅当其值等于你传递参数的条目),等等.这些操作以前需要锁定整个表,因为它们需要两个方法调用来完成(例如,如果你使用的是标准实现,则putIfAbsent()需要调用两个方法containsKey()并put()在一个synchronized块内包装Map.)再一次,使用这些方法获得更大的吞吐量,避免锁定整个表格.


kap*_*pex 10

同步这些操作在这里没有任何好处 - 如果您不需要同步,它实际上会降低性能.

ConcurrentHashMap创建原因的是,同步映射(在问题中手动实现或以通常方式实例化)在Collections.synchronizedMap(map)许多线程访问时显示不良性能.Put和get操作是阻塞的,因此所有其他线程必须等待并且不能同时访问映射.本ConcurrentHashMap-正如其名字暗示-允许在另一方面并发访问.如果添加同步,则会失去此优势.

  • @gaurav这应该是同步的.但我不是使用同步,而是使用`putIfAbsent`或`computeIfAbsent`这两个方法(它们都是ConcurrentMap的原子操作). (2认同)