ConcurrentHashMap 概览
- 并发控制:通过锁住单个Hash槽位而非整个HashMap来提升并发性能。
- 核心机制:CAS(比较并交换)、锁Hash槽位、volatile关键字。
ConcurrentHashMap 方法分析
- put():
- 使用CAS和Synchronized确保线程安全和数据一致性。
- get():
- 不需要加锁,可以与写操作并行执行。
- 利用volatile修饰Node数组,确保修改操作的可见性。
读写冲突问题
- 读写冲突分类:
- 类型一:写操作在read操作结束前完成。通过volatile确保所有线程获得最新值。
- 类型二:写操作在read操作结束后完成。导致弱一致性,读操作可能获取到旧值。
volatile 关键字分析
- 作用:确保变量的可见性,所有线程都直接从主存中读取数据。
- 局限性:不保证操作的原子性,如
a++
操作可能在读取和写入之间被其他线程干扰。
ConcurrentHashMap 并发扩容
- 扩容过程:
- 初始化新表:创建更大容量的Node数组。
- 标记迁移:使用forwardingNode和特殊hash值(MOVED == -1)标记正在迁移的桶。
- 多线程参与:其他线程可以通过helpTransfer方法协助数据迁移。
- 并发迁移数据:遍历旧表,将节点重新哈希并插入新表。
- 完成迁移并原子切换:通过CAS操作将新表设置为当前表,保证数据一致性。
ConcurrentHashMap 锁机制
- 锁的对象:hash槽的头结点。
- 源码分析:
synchronized (f)
中的f
即为头结点,确保了对特定槽位的操作是线程安全的。
ConcurrentHashMap 对 null 值的处理
- 为什么不能放 null:
- 避免二义性问题:在多线程环境下,无法确定null是因为键的值本身为null,还是键被删除。
- 与 HashMap 的区别:
- HashMap设计为线程不安全,主要用于单线程场景,不存在上述二义性问题。
常见误解
- 关于null的误解:认为null key或value会影响CAS或加锁操作,这是错误的。Node对象的创建不依赖于key或value是否为null。