2014-09-23 44 views
14

在ConcurrentHashMap(put(),remove()等)上执行所有非retreival操作是否需要封装在synchronized(this)块中?我知道所有这些操作都是线程安全的,那么这样做有没有真正的好处/需要?唯一使用的操作是put()remove()ConcurrentHashMap需要包装在同步块中吗?

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); 
    } 
    ... 
} 

回答

35

不,您正在失去ConcurrentHashMap的好处。您也可以被使用与​​或synchronizedMap()一个HashMap锁定整个表(这是你做什么,在​​包装操作时,因为隐含的显示器是整个对象实例。)

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

一旦你正在使用ConcurrentHashMap,(put()remove()等)成为借助于锁条带化等在执行的原子的所有标准地图的方法。唯一的折衷是像size()isEmpty()这样的方法可能不一定会返回准确的结果,因为它们唯一可能的方式是锁定整个表的所有操作。

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

6

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

创建ConcurrentHashMap的原因是,当许多线程访问时,同步映射(无论是通过手工方式在问题中实现,还是以通常的方式与Collections.synchronizedMap(map)实例化)都表现不佳。放置并获取操作是阻塞的,因此所有其他线程必须等待并且不能并发访问地图。另一方面,ConcurrentHashMap - 顾名思义 - 允许并发访问。如果添加同步,则会失去此优势。

相关问题