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

时间:2014-09-23 15:06:38

标签: java synchronized concurrenthashmap

ConcurrentHashMap(put()remove()等)上的所有非retreival操作是否需要包含在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);
    }
    ...
}

2 个答案:

答案 0 :(得分:51)

不,你这样做会失去ConcurrentHashMap的好处。您也可以使用HashMap synchronizedsynchronizedMap()来锁定整个表格(这是您在synchronized中包装操作时所执行的操作,因为监视器隐含的是整个对象实例。)

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

使用ConcurrentHashMap后,所有标准地图方法(put()remove()等)都会因实施中的锁定条带等而变为原子。唯一的权衡是像size()isEmpty()这样的方法可能不一定会返回准确的结果,因为它们可以用于锁定整个表的所有操作。

ConcurrentMap interface接口还添加了新的原子复合操作,例如putIfAbsent()(只有当密钥不在地图中时才放置东西),remove()同时接受键和值(删除一个条目只有当它的值等于你传递的参数时)等。这些操作过去需要锁定整个表,因为它们需要两个方法调用来完成(例如putIfAbsent()需要调用containsKey()put(),包含在一个synchronized块中,如果您使用的是标准Map实现。)再一次,您可以通过避免锁定整个表来获得更大的吞吐量。

答案 1 :(得分:10)

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

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