ConcurrentHashMap和Collections.synchronizedMap(Map)有什么区别?

Hen*_*ing 577 java concurrency dictionary

我有一个Map,它将被多个线程同时修改.

Java API中似乎有三种不同的同步Map实现:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

据我所知,这Hashtable是一个旧的实现(扩展过时的Dictionary类),后来经过调整以适应Map界面.虽然它同步的,但似乎存在严重的可扩展性问题,并且不鼓励新项目.

但是其他两个怎么样?返回的地图Collections.synchronizedMap(Map)ConcurrentHashMaps 之间有什么区别?哪一种适合哪种情况?

Yuv*_*dam 410

根据您的需求,使用ConcurrentHashMap.它允许从多个线程并发地修改Map,而无需阻止它们.Collections.synchronizedMap(map)创建阻塞Map会降低性能,尽管确保一致性(如果使用得当).

如果需要确保数据一致性,请使用第二个选项,并且每个线程都需要具有最新的地图视图.如果性能至关重要,请使用第一个,并且每个线程仅将数据插入到地图中,读取发生的频率较低.

  • 另请注意,ConcurrentHashMap不允许使用null键或值.所以它们不是同步地图的平等替代品. (118认同)
  • 我想你应该读一下[http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/](http://ria101.wordpress.com/2011/12/12/ConcurrentHashMap的规避-A-共误用/) (23认同)
  • 查看源代码,同步映射只是一个具有一个互斥(阻塞)的实现,而ConcurrentHashMap处理并发访问更复杂 (7认同)
  • @AbdullahShaikh该文章中提出的问题已在Java 7中得到修复,并且在Java 8中进行了进一步的改进. (4认同)
  • @hengxin:只要执行包含多个查询或地图更新的操作,或者在迭代地图时,就必须在地图上手动同步以确保一致性.同步映射仅保证地图上单个操作(方法调用)的一致性,这使得它通常毫无价值,因为大多数实际操作都是非平凡的,因此您必须手动同步. (4认同)

Ser*_*hyk 231

???????????????????????????????????????????????????????????????????????????????
?   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   ? 
???????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

关于锁定机制: Hashtable 锁定对象,同时ConcurrentHashMap锁定.

  • `Hashtable`不是锁定地图的一部分.看看实现.它使用`synchronized`键而没有提供锁定,因此它基本上意味着它在每个操作中锁定整个`hashtable`. (12认同)
  • synchronizedMap怎么样? (6认同)
  • 我打印桌子并以每个5美元的价格出售;).好的@shevchyk (4认同)
  • Collections.syncronizedMap行为类似于支持映射,除了所有方法都是线程安全的 (3认同)

Mic*_*rdt 141

"可扩展性问题"以Hashtable完全相同的方式呈现Collections.synchronizedMap(Map)- 它们使用非常简单的同步,这意味着只有一个线程可以同时访问地图.

当你有简单的插入和查找时(除非你非常密集地进行),这不是什么大问题,但是当你需要遍历整个Map时会出现一个大问题,这可能需要很长时间才能完成一个大的Map - 而一个线程就是这样做的,所有其他人都必须等待,如果他们想插入或查找任何东西.

ConcurrentHashMap使用非常复杂的技术,以减少同步的需要,并允许由多个线程并行读取访问,而无需同步,更重要的是,提供了Iterator一个无需同步,甚至允许地图互为作用过程中被修改(尽管它不保证是否不会返回在迭代期间插入的元素).

  • 现在这就是我想要的!:)没有同步的迭代器只是纯粹的甜蜜!Thansk的信息!:)(: (4认同)
  • @Michael Borgwardt的ConcurrentHashmap例如.假设有多个线程.其中一些正在更新地图,其中一些正在从同一地图获取数据.所以在这种情况下,当线程试图读取是保证他们会得到,因为读者线程已经更新,不必持有锁的最新数据. (4认同)

Bil*_*ell 33

当你可以使用它时,首选ConcurrentHashMap - 尽管它至少需要Java 5.

它被设计为在被多个线程使用时可以很好地扩展.当一次只有一个线程访问Map时,性能可能稍差,但当多个线程同时访问映射时,性能会明显提高.

我发现了一个博客条目,它从优秀的书籍Java Concurrency In Practice中重现了一个表,我完全推荐了这本书.

Collections.synchronizedMap真正有意义,只有当你需要包含一些具有其他特征的地图时,可能是某种有序的地图,比如TreeMap.

  • Java并发参考的+1 - 必读 (6认同)
  • 是的 - 似乎我在其他所有答案中都提到了这本书! (2认同)

Pix*_*ech 32

这两者之间的主要区别在于,它ConcurrentHashMap只会锁定正在更新的部分数据,而其他部分数据可以被其他线程访问.但是,Collections.synchronizedMap()在更新时会锁定所有数据,其他线程只能在释放锁时访问数据.如果有许多更新操作和相对少量的读取操作,则应选择ConcurrentHashMap.

另外一个区别是ConcurrentHashMap不会保留传入Map的元素顺序.它与HashMap存储数据时类似.无法保证元素顺序得以保留.虽然Collections.synchronizedMap()将保留传入的Map的元素顺序.例如,如果传递TreeMapConcurrentHashMap,则元素顺序ConcurrentHashMap可能与顺序中的顺序不同TreeMap,但Collections.synchronizedMap()会保留顺序.

此外,ConcurrentHashMap可以保证ConcurrentModificationException在一个线程更新映射并且另一个线程正在遍历从映射获得的迭代器时没有抛出.但是,Collections.synchronizedMap()不保证这一点.

一个帖子证明了这两者之间的差异ConcurrentSkipListMap.


Zac*_*ena 12

像往常一样,涉及并发 - 开销 - 速度权衡.您确实需要考虑应用程序的详细并发要求来做出决策,然后测试代码以确定它是否足够好.


Sat*_*ish 12

ConcurrentHashMap,锁定应用于段而不是整个Map.每个段管理自己的内部哈希表.锁仅适用于更新操作.Collections.synchronizedMap(Map)同步整个地图.


Ram*_*nti 11

同步地图:

同步映射与Hashtable也没有太大差别,并且在并发Java程序中提供类似的性能.Hashtable和SynchronizedMap之间的唯一区别是SynchronizedMap不是遗留的,您可以使用Collections.synchronizedMap()方法包装任何Map以创建它的同步版本.

ConcurrentHashMap的:

ConcurrentHashMap类提供标准HashMap的并发版本.这是对Collections类中提供的synchronizedMap功能的改进.

与Hashtable和Synchronized Map不同,它永远不会锁定整个Map,而是将段分割成段,并在那些上完成锁定.如果读取器线程的数量大于写入器线程的数量,则它的性能会更好.

默认情况下,ConcurrentHashMap分为16个区域并应用锁定.初始化ConcurrentHashMap实例时,可以设置此默认编号.在特定段中设置数据时,将获取该段的锁定.这意味着如果两个更新各自影响单独的存储桶,则它们仍可以安全地同时执行,从而最大限度地减少锁争用并最大限度地提高性能.

ConcurrentHashMap不会抛出ConcurrentModificationException

如果一个线程试图修改它而另一个线程迭代它,则ConcurrentHashMap不会抛出ConcurrentModificationException

synchornizedMap和ConcurrentHashMap之间的区别

Collections.synchornizedMap(HashMap)将返回一个几乎等同于Hashtable的集合,其中Map上的每个修改操作都锁定在Map对象上,而在ConcurrentHashMap的情况下,通过将整个Map划分为基于并发级别的不同分区来实现线程安全性并且只锁定特定部分而不是锁定整个Map.

ConcurrentHashMap不允许null键或null值,而synchronized HashMap允许一个null键.

类似的链接

链接1

LINK2

绩效比较


elj*_*nso 9

你是对的HashTable,你可以忘掉它.

您的文章提到了这样一个事实:虽然HashTable和同步包装类通过一次只允许一个线程访问映射来提供基本的线程安全性,但这不是"真正的"线程安全性,因为许多复合操作仍需要额外的同步,例:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}
Run Code Online (Sandbox Code Playgroud)

但是,不要认为ConcurrentHashMap对于HashMap具有synchronized如上所示的典型块的a而言,这是一个简单的替代方案.阅读文章,了解其复杂性更好.


小智 7

这里有几个:

1)ConcurrentHashMap仅锁定Map的一部分,但SynchronizedMap锁定整个MAp.
2)ConcurrentHashMap比SynchronizedMap具有更好的性能,并且可扩展性更强.
3)如果是多个读者和单个编写者,ConcurrentHashMap是最佳选择.

本文来自ConcurrentHashMap与Java中的哈希表之间的区别


Sum*_*ada 7

我们可以使用ConcurrentHashMap和synchronisedHashmap和Hashtable来实现线程安全.但是,如果你看一下他们的架构,会有很多不同.

  1. synchronisedHashmap和Hashtable

两者都将保持对象级别的锁定.所以如果你想执行像put/get这样的任何操作,那么你必须首先获得锁.同时,不允许其他线程执行任何操作.所以一次只有一个线程可以对此进行操作.所以等待时间会增加.我们可以说与ConcurrentHashMap比较时性能相对较低.

  1. 的ConcurrentHashMap

它将保持段级别的锁定.它有16个段,默认情况下将并发级别维持在16.所以一次,16个线程可以在ConcurrentHashMap上运行.而且,读操作不需要锁定.因此任意数量的线程都可以对其执行get操作.

如果thread1想要在段2中执行put操作并且thread2想要在段4上执行put操作,那么这里允许它.意味着,16个线程可以一次对ConcurrentHashMap执行更新(put/delete)操作.

这样等待时间会减少.因此,性能相对于synchronisedHashmap和Hashtable相对更好.


Pre*_*raj 6

的ConcurrentHashMap

  • 在项目中需要非常高的并发性时,应该使用ConcurrentHashMap.
  • 没有同步整个地图是线程安全的.
  • 使用锁完成写操作时,读操作可以非常快.
  • 对象级别没有锁定.
  • 在hashmap桶级别,锁定的粒度更精细.
  • 如果一个线程尝试修改它而另一个线程迭代它,则ConcurrentHashMap不会抛出ConcurrentModificationException.
  • ConcurrentHashMap使用多种锁.

SynchronizedHashMap

  • 对象级别的同步.
  • 每次读/写操作都需要获取锁.
  • 锁定整个集合是一种性能开销.
  • 这实际上只允许访问整个映射的一个线程并阻止所有其他线程.
  • 它可能会引起争用.
  • SynchronizedHashMap返回Iterator,它在并发修改时失败.

资源


sta*_*lue 5

ConcurrentHashMap 针对并发访问进行了优化。

访问不会锁定整个映射,而是使用更细粒度的策略,从而提高可扩展性。还有专门针对并发访问的功能增强,例如并发迭代器。