Map
- 采用了数组加链表的方式存储(横向数组,纵向链表),当有同一hash值得数据会被房到同意数组后面形成链表
HashMap(默认16长度)
- put
int hash = hash(key); 获取hash值
int i = indexFor(hash, table.length); tab[hash&(n-1)]返回Map table索引位置(为了解决均匀散列索引)
循环遍历链表,如果当前Entry hash值与key跟传入的key相等则将新值赋值给旧值,返回旧值
否则创建新的Entry,并将空的tab[hash&(n-1)]赋值给Entry.next
- get
<1>计算hash值
<2>遍历链表,根据int i = indexFor(hash, table.length);Map table数组索引值位置
HashTable(默认11长度)
-
HashTable使用了synchronized进行加锁
-
int hash = hash(key);获取该key的哈希值
-
int index = (hash & 0x7FFFFFFF) % tab.length; 获取该key在table数组的索引下标,得到该索引下的链表
ConcurrentHashMap(默认16长度的Segment(段),16个并发)
初始化:默认初始化16段(Segment),16个并发数,在第一段初始化长度为2的HashEntry数组(主要作用是保存第一次初始化的时候的参数如:长度,扩展阈值)
在操作put与get的时候使用了Unsafe非阻塞同步机制(基于硬件级别的CAS算法),Segment操作时会经过两次hash运算,
第一次hash:(hash(key) >>> segmentShift(28)) & segmentMask(15)得到Segment的位置
第二次hash是用第一次hash值的基础上(tab.length - 1) & hash得到HashEntry数组的索引,从而得到链表
-
ConcurrentHashMap结构为先分为16个Segment段,在每个Segment再已横向HashEntry数组,再纵向链表的形式保存数据,
操作是采用ReentrantLock锁住一个Segment里面HashEntry,保证线程安全而不会锁住整个Map -
put操作
先获取key的hash值计算该key在Segment位置