java - ConcurrentHashMap之和Collections.synchronizedMap( Map )间有何区别?

  显示原文与译文双语对照的内容

我有一个由多个线程同时修改的映射。

在javaapi中似乎有三个不同的同步映射实现:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

据我所知,Hashtable 是一个旧的实现( 扩展过时的Dictionary 类),它后来被改编为适合 Map 接口。 虽然同步,它似乎已经严重可伸缩性问题气馁新项目。

那另外两个? Collections.synchronizedMap(Map)ConcurrentHashMap 返回的映射有什么不同? 哪一种情况适合哪一种情况?

时间:

根据你的需求,使用 ConcurrentHashMap 。 它允许同时修改来自多个线程的映射而不需要阻止它们。 Collections.synchronizedMap(map) 创建的阻塞映射会降低性能,但确保一致性( 如果使用得当的话) 。

如果需要确保数据一致性,请使用第二个选项,每个线程都需要有最新的映射视图。 使用第一个如果性能是至关重要的,并且每个线程只插入数据的地图,读取发生的频率更低。

"可扩展性问题" HashtableCollections.synchronizedMap(Map) 出现在完全相同的方式——他们用非常简单的同步,这意味着只有一个线程可以访问地图在同一时间。

当你有简单的插入和查找( 除非你做得非常认真) 时,这并没有多大问题,但是当你需要迭代整个映射时,这将成为一个大问题,如果需要插入或者查找任何其他映射,则需要等待整个映射。

ConcurrentHashMap 使用非常复杂的技术来减少同步的需求,并允许多个线程并行读取并行读取访问,更重要的是,它提供了不同步的Iterator,甚至允许在迭代( 尽管它不保证迭代期间插入的元素是否会被返回) 期间修改映射。


╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║ Property ║ HashMap ║ Hashtable ║ ConcurrentHashMap ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║ Null ║ allowed ║ not allowed ║
║ values/keys ║ ║ ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║Is thread-safe ║ no ║ yes ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Lock ║ not ║ locks the portion of ║ 
║ mechanism ║ applicable ║ map ║ 
╠═══════════════╬═══════════════════╩═══════════════════╦═════════════════════╣
║ Iterator ║ fail-fast ║ fail-safe ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

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

它被设计成在多个线程使用时扩展。 当一个线程一次访问映射时,性能可能会稍差一些,但当多个线程同时访问映射时,性能会显著下降。

我发现了一个博客条目,它在实践中从优秀的图书 Java并发中复制了一个表,我完全推荐。

Collections.synchronizedMap 意义只如果你需要结束地图和其他特点,也许某种命令地图,像treemap。

像往常一样,有concurrency--overhead--speed权衡。 你真的需要考虑应用程序的详细并发需求以做出决定,然后测试代码是否足够好。

ConcurrentHashMap 中,锁应用于一个线段而不是整个映射。 每个段管理自己的内部哈希表。 锁只用于更新操作。 Collections.synchronizedMap(Map) 同步整个映射。

你对 HashTable 是对的,你可以忘记它。

文章提到这样一个事实,尽管hashtable和同步包装类提供基本thread-safety通过一次只允许一个线程访问地图,这不是'真'thread-safety因为许多复合操作仍然需要额外的同步,例如:


synchronized (records) {
 Record rec = records.get(id);
 if (rec == null) {
 rec = new Record(id);
 records.put(id, rec);
 }
 return rec;
}

然而,不要认为 ConcurrentHashMap 是一个简单的选择与一个典型的synchronizedHashMap 块如上所示。 阅读这篇文章以更好地理解它的复杂性。

...