我有一个地图,该地图将同时被多个线程修改。 java
Java API中彷佛有三种不一样的同步Map实现: 安全
Hashtable
Collections.synchronizedMap(Map)
ConcurrentHashMap
据我了解, Hashtable
是一个旧的实现(扩展了过期的Dictionary
类),后来对其进行了调整以适合Map
接口。 虽然它是同步的,但彷佛存在严重的可伸缩性问题 ,所以不建议用于新项目。 并发
可是其余两个呢? Collections.synchronizedMap(Map)
和ConcurrentHashMap
返回的Collections.synchronizedMap(Map)
之间有什么区别? 哪种适合哪一种状况? app
在ConcurrentHashMap
,该锁将应用于段而不是整个Map。 每一个段都管理本身的内部哈希表。 该锁仅适用于更新操做。 Collections.synchronizedMap(Map)
同步整个地图。 ide
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗ ║ Property ║ HashMap ║ Hashtable ║ ConcurrentHashMap ║ ╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ ║ Null ║ allowed ║ not allowed ║ ║ values/keys ║ ║ ║ ╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣ ║Is thread-safe ║ no ║ yes ║ ╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣ ║ Lock ║ not ║ locks the whole ║ locks the portion ║ ║ mechanism ║ applicable ║ map ║ ║ ╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣ ║ Iterator ║ fail-fast ║ weakly consistent ║ ╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝
关于锁定机制: Hashtable
锁定对象 ,而ConcurrentHashMap
仅锁定bucket 。 性能
二者之间的主要区别在于ConcurrentHashMap
将仅锁定正在更新的数据部分,而其余线程能够访问其余部分数据。 可是, Collections.synchronizedMap()
将在更新时锁定全部数据,其余线程仅在释放锁定后才能访问数据。 若是更新操做不少而读取操做相对较少,则应选择ConcurrentHashMap
。 spa
另一个区别是ConcurrentHashMap
不会保留传入的Map中元素的顺序。它在存储数据时相似于HashMap
。 不能保证保留元素顺序。 虽然Collections.synchronizedMap()
将保留在经过Map的元素顺序。例如,若是你传递一个TreeMap
来ConcurrentHashMap
,这些元素才能在ConcurrentHashMap
可能不同,在顺序TreeMap
,但Collections.synchronizedMap()
将保留顺序。 .net
此外, ConcurrentHashMap
能够保证在一个线程更新映射而另外一个线程遍历从映射得到的迭代器时,不会引起ConcurrentModificationException
。 可是,对此不保证Collections.synchronizedMap()
。 线程
有一篇文章展现了这二者的区别以及ConcurrentSkipListMap
。 code
并发哈希图
SynchronizedHashMap