ConcurrentHashMap 的实现方式和 Hashtable 不同,不采用独占锁的形式,更高效,其中在 jdk1.7 和 jdk1.8 中实现的方式也略有不同。
Jdk1.7 中采用分段锁和 HashEntry 使锁更加细化。ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。
Jdk1.8 利用 CAS+synchronized 来保证并发更新的安全,当然底层采用数组+链表+红黑树的存储结构。
- table 中存放 Node 节点数据,默认 Node 数据大小为 16,扩容大小总是 2^N。
- 为了保证可见性,Node 节点中的 val 和 next 节点都用 volatile 修饰。
- 当链表长度大于 8 时,会转换成红黑树,节点会被包装成 TreeNode放在TreeBin 中。
- put():1. 计算键所对应的 hash 值;2. 如果哈希表还未初始化,调用 initTable() 初始化,否则在 table 中找到 index 位置,并通过 CAS 添加节点。如果链表节点数目超过 8,则将链表转换为红黑树。如果节点总数超过,则进行扩容操作。
- get():无需加锁,直接根据 key 的 hash 值遍历 node。