[英]How does ConcurrentHashMap work internally?
我正在阅读有关 Java 并发的 Oracle 官方文档,我想知道返回的Collection
之间有什么区别
public static <T> Collection<T> synchronizedCollection(Collection<T> c);
并使用例如
ConcurrentHashMap
。 我假设我在HashMap
上使用synchronizedCollection(Collection<T> c)
。 我知道一般来说,同步集合本质上只是我的HashMap
的装饰器,因此很明显ConcurrentHashMap
的内部结构有所不同。 你有关于这些实现细节的一些信息吗?
编辑:我意识到源代码是公开可用的: ConcurrentHashMap.java
我会阅读ConcurrentHashMap的来源,因为它的细节相当复杂。 总之它有
ConcurrentHashMap
与java.util.HashTable
类非常相似,除了ConcurrentHashMap
提供比HashTable
或synchronizedMap
更好的并发性。 ConcurrentHashMap
在您读取 Map 时不会锁定它。 此外, ConcurrentHashMap
在写入时不会锁定整个Map
。 它只在内部锁定正在写入的Map
部分。
另一个区别是,如果ConcurrentHashMap
在迭代时发生更改,则 ConcurrentHashMap 不会抛出ConcurrentModificationException
。 Iterator
并非设计为由多个线程使用,而synchronizedMap
可能会抛出ConcurrentModificationException
这篇文章帮助我理解了为什么 ConcurrentHashMap 比 Hashtable 更好并且和 HashMap 一样好
Hashtable 提供对其条目的并发访问,但需要注意的是,整个映射被锁定以执行任何类型的操作。 虽然这种开销在正常负载下的 web 应用程序中是可以忽略的,但在重负载下,它可能会导致响应时间延迟和服务器无缘无故地负担过重。
这就是 ConcurrentHashMap 的用武之地。它们提供了 Hashtable 的所有功能,并且性能几乎与 HashMap 一样好。 ConcurrentHashMap 通过一个非常简单的机制来实现这一点。 该集合默认维护一个包含 16 个锁的列表,而不是地图范围的锁,每个锁用于保护(或锁定)地图的单个存储桶。 这实际上意味着 16 个线程可以一次修改集合(只要它们都在不同的存储桶上工作)。 事实上,这个集合没有执行锁定整个地图的操作。 集合的并发级别,可以在不阻塞的情况下同时修改它的线程数,可以增加。 然而,更高的数字意味着维护这个锁列表的开销更大。
Hashtable
的“可扩展性问题”在Collections.synchronizedMap(Map)
以完全相同的方式存在——它们使用非常简单的同步,这意味着只有一个线程可以同时访问映射。
当您进行简单的插入和查找时,这不是什么大问题(除非您非常密集地执行此操作),但是当您需要遍历整个 Map 时会成为一个大问题,这对于大型 Map 可能需要很长时间 - 而一个线程这样做,所有其他线程如果要插入或查找任何内容都必须等待。
ConcurrentHashMap
使用非常复杂的技术来减少同步的需要,并允许多个线程在没有同步的情况下并行读取访问,更重要的是,它提供了一个不需要同步的迭代器,甚至允许在交互期间修改 Map(尽管它不保证是否会返回在迭代期间插入的元素)。
synchronizedCollection()返回的是一个对象,其所有方法都在this上同步,因此此类包装器上的所有并发操作都被序列化。 ConcurrentHashMap 是一个真正的并发容器,具有优化的细粒度锁定以保持尽可能低的争用。 看看源代码,你会看到它里面的内容。
ConcurrentHashMap 实现了提供并发性的 ConcurrentMap。 在内部,它的迭代器被设计为一次仅由一个线程使用,以保持同步。 此映射在并发中被广泛使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.