HashMap ConcurrentHashMap解读
前言:
常见的关于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解读的更多相关文章
- HashTable & HashMap & ConcurrentHashMap 原理与区别
一.三者的区别 HashTable HashMap ConcurrentHashMap 底层数据结构 数组+链表 数组+链表 数组+链表 key可为空 否 是 否 value可为空 否 是 否 ...
- 深入理解HashMap+ConcurrentHashMap的扩容策略
前言 理解HashMap和ConcurrentHashMap的重点在于: (1)理解HashMap的数据结构的设计和实现思路 (2)在(1)的基础上,理解ConcurrentHashMap的并发安全的 ...
- Jdk8 Hashmap ConcurrentHashMap
JDK1.8 Hashmap JDK1.8 ConcurrentHashMap 不采用segment而采用 synchronized (f) f = table[i]; 减小锁的力度 设计了MOVE ...
- java多线程之hashmap concurrenthashmap的状态同步
最近在高并发的系统中发现,concurrenthashmap除了大家熟知的避免循环期间发生ConcurrentModificationException异常外,还有重要的一点是Retrievals r ...
- HashMap完全解读
一.什么是HashMap 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Has ...
- HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!
前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...
- ConcurrentHashMap 解读
初始化: 问题:如何当且仅只有一个线程初始化table private final Node<K,V>[] initTable() { Node<K,V>[] tab; int ...
- Java7/8 HashMap ConcurrentHashMap
网上关于 HashMap 和 ConcurrentHashMap 的文章确实不少,不过缺斤少两的文章比较多,所以才想自己也写一篇,把细节说清楚说透,尤其像 Java8 中的 ConcurrentHas ...
- HashMap? ConcurrentHashMap?
前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...
随机推荐
- [ DLPytorch ] 线性回归&Softmax与分类模型&多层感知机
线性回归 基础知识 实现过程 学习笔记 批量读取 torch_data = Data.TensorDataset(features, labels) dataset = Data.DataLoader ...
- 一个简单insert 语句执行 40ms 原因剖析
背景:一个简单的带有主键的insert 语句,居然要 40ms ,开发受不了,要求降低 因此我们要关注的的 数据从插入落地的IO 中间都干了什么 一.MySQL的文件 首先简单介绍一下MySQL的数据 ...
- The property does not exist in XML namespace
自定义依赖属性,绑定在xaml文件中,无问题. 但是编译失败,报 The property does not exist in XML namespace 错误. 发现如果依赖属性定义在本程序集中,在 ...
- KVM的客户机可以使用的存储
KVM的虚拟机可以直接使用宿主机器内的存储设备,比如可以把宿主机器内的硬盘直接暴露给 虚拟机挂载使用 -hda /dev/sfa(宿主机的设备文件) 还可以把镜像文件挂接到虚拟机,作为虚拟机的存储设备 ...
- [转]:Ubuntu 下Apache安装和配置
[转]:Ubuntu 下Apache安装和配置_服务器应用_Linux公社-Linux系统门户网站 https://www.linuxidc.com/Linux/2013-06/85827.htm ...
- static在c\c++中的作用(翁恺c++公开课[28-29]学习笔记)
static相对来说是一个较复杂的修饰符,c++中的static在c的基础之上又包含了static在类中的应用(也就是说多了static的成员变量和static的成员函数):c\c++中静态变量.对象 ...
- [Android实例] Android网络收音机项目(内含源码)
======================帖子内容===================================最近喜欢听广播,但是搜索了一下,苦于网上没有Android的网络收音机项目的例 ...
- Java后端 带File文件及其它参数的Post请求
http://www.roak.com Java 带File文件及其它参数的Post请求 对于文件上传,客户端通常就是页面,在前端web页面里实现上传文件不是什么难事,写个form,加上enctype ...
- 39 (guava包)AbstractScheduledService的使用
package com.da.tool.guava; import com.google.common.util.concurrent.AbstractScheduledService; import ...
- 解决新建maven工程没有web.xml的问题
首先确定创建maven工程时选择的打包方式为 war 创建后如图所示没有web.xml文件以及相关文件夹,错误信息:缺少web.xml文件 解决方法: 右击maven项目,找到ProjectFacet ...