【JDK 源码分析】ConcurrentHashMap 底层结构

简介: 【1月更文挑战第27天】【JDK 源码分析】ConcurrentHashMap 底层结构

ConcurrentHashMap针对JDK 1.7JDK 1.8版本上实现有不同。先来看看JDK 1.7版本的ConcurrentHashMap的底层实现。

JDK 1.7版本的ConcurrentHashMap底层维护了:Segments数组+HashEntry数组+链表,采用分段锁保证线程安全。

一个ConcurrentHashMap中有一个Segments数组,一个Segments中存储一个HashEntry数组,每个HashEntry是一个链表结构的元素。

segment继承自ReentrantLock锁。 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问,实现了真正的并发访问。可以通过构造函数指定,数组扩容不会影响其他的segmentget无需加锁,volatile保证内存可见性。

JDK 1.8版本的ConcurrentHashMap底层维护了:Synchronized + CAS +Node + 红黑树。Nodevalnext都用volatile保证,保证可见性。查找,替换,赋值操作都使用CAS

1.1 内部属性:

先对ConcurrentHashMap中的几个重要属性进行了解:

// ConcurrentHashMap 最大容量:
private static final int MAXIMUM_CAPACITY = 1 << 30;
// ConcurrentHashMap 默认容量(和HashMap一致):
private static final int DEFAULT_CAPACITY = 16;
// ConcurrentHashMap 最大可能的数组大小:
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 默认的并发级别(不适用,为了兼容之前的版本):
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
// 默认的负载因子:
private static final float LOAD_FACTOR = 0.75f;
// 链表转红黑树阈值:
static final int TREEIFY_THRESHOLD = 8;
// 红黑树退化成链表的阈值:
static final int UNTREEIFY_THRESHOLD = 6;
// 红黑树化时,table数组最小值:
static final int MIN_TREEIFY_CAPACITY = 64;

除了这些定义的常量值,外有几个关键的内部属性:

  • tableNode数组:

HashMap不一样的地方是,ConcurrentHashMap中的table数组使用了volatile关键字进行修饰。

// 第一次新增元素时初始化,始终是2的幂:
transient volatile Node<K,V>[] table;

除了table数组外,还提供了nextTable数组:

// 扩容时用,代表扩容后的数组:
private transient volatile Node<K,V>[] nextTable;
  • Node节点的特殊hash值:
// 转移节点的hash值:
static final int MOVED     = -1; 
// (红黑)树根节点的hash值:
static final int TREEBIN   = -2; 
// 临时保留的hash值:
static final int RESERVED  = -3; 
// 普通节点hash的可用位:
static final int HASH_BITS = 0x7fffffff;
  • 控制table初始化和扩容的字段:
// -1 初始化中
// -n 表示n-1个线程正在扩容中
//  0 使用默认容量进行初始化
// >0 使用多少容量
private transient volatile int sizeCtl;

1.2 Node 节点:

这里我们重点关注的是Node中的两个属性valnext。和HashMap最大的区别就是,这两个属性使用了volatile关键字进行修饰,保证了这个两个变量的可见性以及有序性

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;
  // 构造器、操作方法......
}

关于volatile关键字的具体作用,需要参考一下JUC并发部分的文章,这里不过度解析。

相关文章
|
4月前
|
Java
【JDK 源码分析】HashMap 操作方法
【1月更文挑战第27天】【JDK 源码分析】HashMap Put 元素 初始化
|
5月前
|
Java
Integer类【JDK源码分析】
Integer类【JDK源码分析】
22 0
|
5月前
|
存储 网络协议 Java
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(二)
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
38 0
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(二)
|
3月前
|
存储 网络协议 Java
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
15 0
|
4月前
|
安全 Java
【JDK 源码分析】HashMap 线程安全问题分析
【1月更文挑战第27天】【JDK 源码分析】HashMap 线程安全问题分析
|
4月前
|
存储 Java
【JDK 源码分析】HashMap 底层结构
【1月更文挑战第27天】【JDK 源码分析】HashMap 底层结构
|
5月前
|
安全 Java 索引
认真学习jdk1.7下ConcurrentHashMap的实现原理
认真学习jdk1.7下ConcurrentHashMap的实现原理
60 0
|
5月前
|
网络协议 Java Unix
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(一)
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
52 0
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(一)
|
5月前
|
机器学习/深度学习 存储 Java
认真学习jdk1.8下ConcurrentHashMap的扩容机制
认真学习jdk1.8下ConcurrentHashMap的扩容机制
36 0
|
5月前
|
机器学习/深度学习 存储 Java
认真学习jdk1.8下ConcurrentHashMap的实现原理
认真学习jdk1.8下ConcurrentHashMap的实现原理
33 0
认真学习jdk1.8下ConcurrentHashMap的实现原理