前言:

常见的关于HahsMap与ConcurrentHashMap的问题:

数据结构、线程安全、扩容、jdk1.7 HashMap死循环、jdk1.8 HashMap红黑树、容量必须是2的冥次

HashMap

数据结构:数组,单向链表

线程安全:不安全,HashTable线程安全,但是全用了 synchronized ,性能低

一、jdk1.7中

①:对HashMap初始化进行初始化;

初始化HashMap的 threshold 字段,通过因子算出,默认为0.75,算出来是16 * 0.75为12;

初始化hash种子信息;

保证了HashMap的容量是2的冥次。为什么HashMap的容量必须是2的冥次,因为可以增加有效长度,减少hash碰撞,关于hash碰撞:https://blog.csdn.net/qq_35583089/article/details/80048285

②:添加Entry对象,赋值

①:判断当前容量是否到达阈值,例如12

②:扩容

头插法:原先的头会成为新链表的尾部,原先的尾部会成为新链表的头

这里的代码就是为什么不建议并发时使用HashMap的原因,e.next形成死循环,导致CPU 100%卡死,并且线程不安全

二、jdk1.8中

jdk1.8中,当容量超过2的8次方(64)时,使用红黑树替代链表

ConcurrentHashMap

数据结构(jdk1.7):Segment数组,Segment下又有HashEntry,HashEntry为数组+链表

数据结构(jdk1.8):但是在jdk1.8中,起始的数据结构是数组+链表的。但是当单个链表长度

ConcurrentHashMap是一个线程安全的Map类,其通过多个Segment来保存数据,操作不同Segment之间是可以并发的,而操作统计个Segment进行数据的插入时,会进行 ReentrantLock 上锁操作

一、jdk1.7

先看看put方法

public V put(K key, V value) {
ConcurrentHashMap.Segment<K,V> s;
if (value == null)
throw new NullPointerException();
//通过key的hash值算出segment的下标
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (ConcurrentHashMap.Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
//这里会判断对应下标的segment是否存在,不存在会进行初始化
s = ensureSegment(j);
return s.put(key, hash, value, false);
}

下面是Segment.put方法

final V put(K key, int hash, V value, boolean onlyIfAbsent) {
   //尝试获得锁,并开始同步
ConcurrentHashMap.HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);
V oldValue;
try {
ConcurrentHashMap.HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
ConcurrentHashMap.HashEntry<K,V> first = entryAt(tab, index);
for (ConcurrentHashMap.HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key ||
(e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
}
else {
         //和HashMap一样,链表使用头插法,后插入的元素永远在数组的最前面
if (node != null)
node.setNext(first);
else
node = new ConcurrentHashMap.HashEntry<K,V>(hash, key, value, first);
int c = count + 1;
          //超过Segment阈值时,对HashEntry进行扩容
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}

二、jdk1.8

java1.7采用volatile去获取已存在的Segment。java1.8采用的CAS算法,而没用使用Segment进行数据存储

HashMap ConcurrentHashMap解读的更多相关文章

  1. HashTable & HashMap & ConcurrentHashMap 原理与区别

    一.三者的区别     HashTable HashMap ConcurrentHashMap 底层数据结构 数组+链表 数组+链表 数组+链表 key可为空 否 是 否 value可为空 否 是 否 ...

  2. 深入理解HashMap+ConcurrentHashMap的扩容策略

    前言 理解HashMap和ConcurrentHashMap的重点在于: (1)理解HashMap的数据结构的设计和实现思路 (2)在(1)的基础上,理解ConcurrentHashMap的并发安全的 ...

  3. Jdk8 Hashmap ConcurrentHashMap

    JDK1.8 Hashmap JDK1.8 ConcurrentHashMap 不采用segment而采用 synchronized (f)  f = table[i]; 减小锁的力度 设计了MOVE ...

  4. java多线程之hashmap concurrenthashmap的状态同步

    最近在高并发的系统中发现,concurrenthashmap除了大家熟知的避免循环期间发生ConcurrentModificationException异常外,还有重要的一点是Retrievals r ...

  5. HashMap完全解读

    一.什么是HashMap 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Has ...

  6. HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!

    前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...

  7. ConcurrentHashMap 解读

    初始化: 问题:如何当且仅只有一个线程初始化table private final Node<K,V>[] initTable() { Node<K,V>[] tab; int ...

  8. Java7/8 HashMap ConcurrentHashMap

    网上关于 HashMap 和 ConcurrentHashMap 的文章确实不少,不过缺斤少两的文章比较多,所以才想自己也写一篇,把细节说清楚说透,尤其像 Java8 中的 ConcurrentHas ...

  9. HashMap? ConcurrentHashMap?

    前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...

随机推荐

  1. RestTemplate HttpMessageConverter报错的解决方案no suitable HttpMessageConverter

    错误 no suitable HttpMessageConverter found for response type and content type [text/html;charset=UTF- ...

  2. JavaScript - __proto__和prototype,原形

    参考 https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript 区别 构造函数中的prototype创建 ...

  3. Win10中小娜无法搜索本地应用

    解决方案 1.win+X  -    Windows PowerShell(管理员) 2. 输入Get-AppXPackage -Name Microsoft.Windows.Cortana | Fo ...

  4. 入门项目数字手写体识别:使用Keras完成CNN模型搭建(重要)

    摘要: 本文是通过Keras实现深度学习入门项目——数字手写体识别,整个流程介绍比较详细,适合初学者上手实践. 对于图像分类任务而言,卷积神经网络(CNN)是目前最优的网络结构,没有之一.在面部识别. ...

  5. 模块学习--OS

    1 返回当前目录信息 >>> os.getcwd() 'D:\\7_Python\\S14' 2 改变路径 >>> os.chdir('d:\\')#os.chdi ...

  6. DVWA靶机-sql自动注入

    1. 使用dvwa靶机进行sql注入实战(注:当前靶机安全级别为low) 打开sql漏洞,发现输入不同的数字会返回不同的信息, 先尝试手工判断是否存在sql注入 一般sql注入语句像这样,我们构造的是 ...

  7. 基于Modelsim的视频流仿真

    一.前言 最近在看牟新刚写的<基于FPGA的数字图像处理原理及应用>,书中关于FPGA数字图像处理的原理的原理写的非常透彻,在网上寻找了很久都没有找到完整的源代码工程,因此尝试自己做了补充 ...

  8. List模拟栈

    import java.util.LinkedList; import java.util.List; import java.util.Scanner; public class Main<E ...

  9. rhel7 系统服务——unit(单元)

    Linux内核版本从3.10后开始使用systemd管理服务,这也是系统开机后的第一个服务.systemd通过unit单元文件来管理服务. 它保存了服务.设备.挂载点和操作系统其他信息的配置文件,并能 ...

  10. CDQ分治-陌上花开(附典型错误及原因)

    CDQ分治-陌上花开 题目大意 对于给遗传给定的序列: \[ (x,y,z)_1, (x,y,z)_2, (x,y,z)_3, \cdots, (x,y,z)_n \] 求: \[ \sum_{x_i ...