java7,java8 中HashMap和ConcurrentHashMap简介
一:Java7 中的HashMap
结构:
HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。链表中每个元素称为一个Entry 实例,Entry 包含四个属性:key, value, hash 值和用于单向链表的 next。
属性:
capacity:当前数组容量,始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍。
loadFactor:负载因子,默认为 0.75。
threshold:扩容的阈值,等于 capacity * loadFactor
(一)put操作大概过程
在第一个元素插入 HashMap 的时候做一次数组的初始化,就是先确定初始的数组大小,并计算数组扩容的阈值。通过hash(key)找到数组下标后,会先进行 key 判重,如果没有重复,就准备将新值放入到链表的表头。主要逻辑就是先判断是否需要扩容,需要的话先扩容,然后再将这个新的数据插入到扩容后的数组的相应位置处的链表的表头。数组扩容
在插入新值的时候,如果当前的 size 已经达到了阈值(capacity * loadFactor),并且要插入的数组位置上已经有元素,那么就会触发扩容,扩容后,数组大小为原来的 2 倍。
(二)get 操作大概过程
①根据 key 计算 hash 值。
②找到相应的数组下标:hash & (length – 1)。
③遍历该数组位置处的链表,直到找到相等(==或equals)的 key。
二:Java7 中的ConcurrentHashMap
ConcurrentHashMap采用了分段锁的设计,只有在同一个分段内才存在竞态关系,不同的分段锁之间没有锁竞争。相比于对整个Map加锁的设计,分段锁大大的提高了高并发环境下的处理能力。
结构:
整个 ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。每一个Segment中又存储一个类似HashMap的数组链表结构,可以简称为外层数组里面又一个内层数组,内层数组中是一个链表,这样的三维结构。
属性:
concurrencyLevel:Segment 数,默认是 16,也就是说 ConcurrentHashMap 有 16 个 Segments,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。
initialCapacity:初始容量,这个值指的是整个 ConcurrentHashMap 的初始容量,实际操作的时候需要平均分给每个 Segment。
loadFactor:负载因子,之前我们说了,Segment 数组不可以扩容,所以这个负载因子是给每个 Segment 内部使用的。
(一)put操作大概过程
①计算key的hash值确定在某个Segment写
②获得锁,也就是分段锁,操作确定的segment的时,不允许其他线程操作
③和HashMap的操作一样
对于扩容的操作,segment的容量一旦确定后是不能修改的,只能扩容segment [ i ] ,也是和HashMap一样的操作。
(二)get操作大概过程
①计算 hash 值,找到 segment 数组中的具体位置
②segment 中也是一个数组,根据 hash 找到数组中具体的位置
③到这里是链表了,顺着链表进行查找即可
三:Java8 中的HashMap
Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。
Java7 中使用 Entry 来代表每个 HashMap 中的数据节点,Java8 中使用 Node,基本没有区别,都是 key,value,hash 和 next 这四个属性,不过,Node 只能用于链表的情况,红黑树的情况需要使用 TreeNode。
结构:
Java8 中的HashMap里面是一个数组,然后数组中每个元素是一个单向链表,或者是一颗红黑树。当链表长度大于8时转化为红黑树
(一)put操作大概过程
①第一次插入初始化(默认16),不是第一次则计算hash(key)计算下标(判断是否需要扩容)
②判断下标的第一个节点是否是红黑树节点TreeNode ,如果是按照红黑树的插入规则插入。
③如果不是红黑树节点,而是链表节点Node,再判断加入节点后是否大于8。如果是转化为红黑树结构,如果不是,则比较并插入。
扩容也是超过阀定值,则扩容为原来的两倍。
(二)get操作大概过程
①计算 key 的 hash 值,根据 hash 值找到对应数组下标
②判断数组该位置处的元素是否刚好就是我们要找的,如果不是,走第三步
③判断该元素类型是否是 TreeNode,如果是,用红黑树的方法取数据,如果不是,走第四步
⑥遍历链表,直到找到相等(==或equals)的 key
四:Java8 中的ConcurrentHashMap
结构:
和 Java8 的 HashMap 基本上一样,里面是一个数组,然后数组中每个元素是一个单向链表,或者是一颗红黑树。当链表长度大于8时转化为红黑树
(一)put操作大概过程
①如果没有初始化就先调用initTable()方法来进行初始化过程
②如果没有hash冲突就直接CAS插入
③如果还在进行扩容操作就先进行扩容
④如果存在hash冲突,就加锁来保证线程安全,这里有两种情况,一种是链表形式就直接遍历到尾端插入,一种是红黑树就按照红黑树结构插入,
⑤最后一个如果该链表的数量大于阈值8,就要先转换成黑红树的结构,break再一次进入循环
⑥如果添加成功就调用addCount()方法统计size,并且检查是否需要扩容
(二)get操作大概过程
①计算hash值,定位到该table索引位置,如果是首节点符合就返回
②如果遇到扩容的时候,会调用标志正在扩容节点ForwardingNode的find方法,查找该节点,匹配就返回
③以上都不符合的话,就往下遍历节点,匹配就返回,否则最后就返回null
java7,java8 中HashMap和ConcurrentHashMap简介的更多相关文章
- Java7/8 中 HashMap 和 ConcurrentHashMap的对比和分析
大家可能平时用HashMap比较多,相对于ConcurrentHashMap 来说并不是很熟悉.ConcurrentHashMap 是 JDK 1.5 添加的新集合,用来保证线程安全性,提升 Map ...
- java8中hashMap
摘自:http://www.importnew.com/20386.html 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMa ...
- Java8中HashMap扩容算法小计
Java8的HashMap扩容过程主要就是集中在resize()方法中 final Node<K,V>[] resize() { // ...省略不重要的 } 其中,当HashMap扩容完 ...
- Java中HashMap与ConcurrentHashMap的区别
从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心. 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从 ...
- Java7与Java8中的HashMap和ConcurrentHashMap知识点总结
JAVA7 Java7的ConcurrentHashMap里有多把锁,每一把锁用于其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率呢.这 ...
- Java7 和 Java8 中的 ConcurrentHashMap 原理解析
Java7 中 ConcurrentHashMap ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些. 整个 ConcurrentHash ...
- Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析 今天发一篇”水文”,可能很多读者都会表示不理解,不过我想把它作为并发序列文章中不可缺少的一块来介绍.本来以为花不了 ...
- Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析 (转)
阅读前提:本文分析的是源码,所以至少读者要熟悉它们的接口使用,同时,对于并发,读者至少要知道 CAS.ReentrantLock.UNSAFE 操作这几个基本的知识,文中不会对这些知识进行介绍.Jav ...
- Java7/8 中的 HashMap 和 ConcurrentHashMap
Java7 HashMap 数组+链表 Java7 ConcurrentHashMap Segment数组+HashEntry数组链表+ReenTrantLock分段锁 Java8 HashMa ...
随机推荐
- 粒子群算法(PSO)算法解析(简略版)
粒子群算法(PSO) 1.粒子群算法(PSO)是一种基于群体的随机优化技术: 初始化为一组随机解,通过迭代搜寻最优解. PSO算法流程如图所示(此图是从PPT做好,复制过来的,有些模糊) 2.PSO模 ...
- DevOps on AWS之Cloudformation概念介绍篇
Cloudformation的相关概念 AWS cloudformation是一项典型的(IAC)基础架构即代码服务..通过编写模板对亚马逊云服务的资源进行调用和编排.借助cloudformation ...
- thinkphp3.2 批量添加数据
这是我遇到的thinkphp3.2 当中最让我无语的坑 批量添加数据有个方法是 addAll() 这个方法一定要注意数组的键名,一定要整齐!!! 可以在存入数据前,用ksort()方法将数组的键名排序 ...
- UIO,大页内存,CPU亲和性,NUMA机制等
Linux环境下的UIO(Userspace I/O) UIO 用户空间下驱动程序的支持机制.DPDK使用UIO机制使网卡驱动程序运行在用户态,并采用轮询和零拷贝方式从网卡收取报文,提高收发报文的性能 ...
- MyEclipse同时配置多个tomcat
步骤: 1.可以把原有tomcat复制一份,或者下载新的tomcat,如果有必要的话,修改/conf/service.xml文件中tomcat的端口号,避免端口同时暂用出现错误 2.请看一下图片:打开 ...
- Java 笔记——MyBatis 生命周期
1.MyBatis 的生命周期 MyBatis的核心组件分为4个部分. SqlSessionFactoryBuilder (构造器): 它会根据配置或者代码来生成SqISessionFactory,采 ...
- 正则js
匹配中文字符的正则表达式: [\u4e00-\u9fa5] 匹配双字节字符(包括汉字在内):[^\x00-\xff] 匹配空行的正则表达式:\n[\s| ]*\r 匹配HTML标记的正则表达式:/&l ...
- [开源中国]Windows 10 全球市场份额正式超越 Windows 7
Windows 10 全球市场份额正式超越 Windows 7 全球知名科技数据调查公司 Netmarketshare 昨天发布了2018年12月份最新的桌面操作系统份额报告.对于微软来说,这是历史一 ...
- [转帖] 学习 Linux 大页的内存知识
一.在解释什么情况下需要开启大页和为啥需要开启大页前先了解下Linux下页的相关的知识:以下的内容是基于32位的系统,4K的内存页大小做出的计算1)目录表,用来存放页表的位置,共包含1024个目录en ...
- Java之资源文件读取
ClassLoaderWrapper.java package org.utils.resource; import java.io.InputStream; import java.net.URL; ...