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 ...
随机推荐
- jmeter的开启
先申明我以jmeter的3.2版本来描述本文内容,通常不要选择太新的版本,因为新版本容易出现不稳定和不兼容因素.启动jmeter的前提是JDK已经安装和配置,具体的JDK已经安装和配置自行查资料,此处 ...
- svn命令行创建和删除分支和tags
首页 分类首页 目录 原文: http://blog.csdn.net/yangzhongxuan/article/details/7519948 http://zccst.iteye.com/b ...
- 2-Sixteenth Scrum Meeting-20151216
任务安排 成员 今日完成 明日任务 闫昊 写完学习进度记录的数据库操作 写完学习进度记录的数据库操作 唐彬 编写与服务器交互的代码 编写与服务器交互的代码 史烨轩 获取视频url 余帆 本地 ...
- Error:java: 无效的源发行版: 1.8
出现这种情况是gradle或者maven的版本与 本地电脑jdk不一致,具体看一下链接 http://blog.csdn.net/leixingbang1989/article/details/519 ...
- 04-java学习-选择结构
if if else 多重if switch
- 第15周-反射与JSP
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. 网页制作 1.1 制作一个网页index.html,内有字体<FONT>.链接< ...
- iptables之四表五链
iptables可谓是SA的看家本领,需要着重掌握.随着云计算的发展和普及,很多云厂商都提供类似安全组产品来修改机器防火墙. iptables概念 iptables只是Linux防火墙的管理工具而已. ...
- PHP4个载入语句的区别
4个载入语句的区别 include和require的区别: include载入文件失败时(即没有找到该文件),报一个“提示错误”,然后继续执行后续代码: requre载入文件失败时,报错并立即终止执行 ...
- 移动端web开发整理
/* 移动端定义字体的代码 */body { font-family: "Helvetica Neue", Helvetica; } ios端触摸时,会出现一个半透明灰色遮罩 如果 ...
- nginx “403 Forbidden” 错误的原因及解决办法
nginx 的 403 Forbidden errors 表示你在请求一个资源文件但是nginx不允许你查看. 403 Forbidden 只是一个HTTP状态码,像404,200一样不是技术上的错误 ...