一: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简介的更多相关文章

  1. Java7/8 中 HashMap 和 ConcurrentHashMap的对比和分析

    大家可能平时用HashMap比较多,相对于ConcurrentHashMap 来说并不是很熟悉.ConcurrentHashMap 是 JDK 1.5 添加的新集合,用来保证线程安全性,提升 Map ...

  2. java8中hashMap

    摘自:http://www.importnew.com/20386.html 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMa ...

  3. Java8中HashMap扩容算法小计

    Java8的HashMap扩容过程主要就是集中在resize()方法中 final Node<K,V>[] resize() { // ...省略不重要的 } 其中,当HashMap扩容完 ...

  4. Java中HashMap与ConcurrentHashMap的区别

    从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心. 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从 ...

  5. Java7与Java8中的HashMap和ConcurrentHashMap知识点总结

    JAVA7 Java7的ConcurrentHashMap里有多把锁,每一把锁用于其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率呢.这 ...

  6. Java7 和 Java8 中的 ConcurrentHashMap 原理解析

    Java7 中 ConcurrentHashMap ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些. 整个 ConcurrentHash ...

  7. Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析

    Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析 今天发一篇”水文”,可能很多读者都会表示不理解,不过我想把它作为并发序列文章中不可缺少的一块来介绍.本来以为花不了 ...

  8. Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析 (转)

    阅读前提:本文分析的是源码,所以至少读者要熟悉它们的接口使用,同时,对于并发,读者至少要知道 CAS.ReentrantLock.UNSAFE 操作这几个基本的知识,文中不会对这些知识进行介绍.Jav ...

  9. Java7/8 中的 HashMap 和 ConcurrentHashMap

    Java7 HashMap  数组+链表 Java7 ConcurrentHashMap   Segment数组+HashEntry数组链表+ReenTrantLock分段锁 Java8 HashMa ...

随机推荐

  1. QUIC和TCP

    作者:henrystark henrystark@126.com Blog: http://henrystark.blog.chinaunix.net/ 日期:20140626 本文遵循CC协议:署名 ...

  2. arduino新入手体验:三个小实验

    新入手体验:三个小实验 一:一个LED闪烁 控制要求:1个LED灯,每隔50ms闪烁一次 实物连接图: 控制代码: //2018.6/11 ;//定义数字接口10,对应 void setup() { ...

  3. N的阶乘:高精度

    N的阶乘 题目描述  输入一个正整数N,输出N的阶乘. 输入描述: 正整数N(0<=N<=1000) 输出描述:  输入可能包括多组数据,对于每一组输入数据,输出N的阶乘 示例1 输入 4 ...

  4. 《Linux内核设计与实现》Chapter 2 读书笔记

    <Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...

  5. 第一个Spring冲刺周期团队进展报告

    第一天:学习了解ocr技术 第二天:继续学习了解ocr技术 第三天:开始尝试寻找识别灰度化处理的代码 第四天:尝试编译运行灰度化处理代码 第五天:能够灰度化处理图片 第六天:搜索提高识别率的代码 第七 ...

  6. 图文转化(Alpha)版使用说明

    图文转化使用说明 本软件是一款扫描图片上的文字转化成txt或doc格式存储的软件. 现在还只是初期简单的一个实现,软件暂时的界面显示如下: 简介:照片选取的是手机里的本地照片,拍照打开照相机进行拍照. ...

  7. ns3的输入输出奥秘(二) 命令行参数

    命令行参数 (1) UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); echoClient.SetAttribute (&q ...

  8. windows32位系统 安装MongoDB

    今天在win7 32位系统下安装 MongoDB 时,遇到了一堆坑,特此笔记. 一.下载MongoDB 打开官网下载地址:https://www.mongodb.com/download-center ...

  9. Activiti源码:ActivitiEventSupport类中eventListeners的设计

    ActivitiEventSupport类成员eventListeners是使用CopyOnWriteArrayList实现的. public ActivitiEventSupport() { eve ...

  10. Python日志模块简单使用

    def loginfo(info): # create logger logger = logging.getLogger('[cpu and mem]**********') # Set defau ...