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 ...
随机推荐
- [翻译]:Cinemachine 官方文档(0)
目录 Overview : Installation and Getting Started :安装并开始 User Guide :用户指南 What is Cinemachine? : 什么是Cin ...
- [T-ARA][놀아볼래?][要玩吗]
歌词来源:http://music.163.com/#/song?id=22704479 作曲 : 赵英秀/김태현 [作曲 : 赵英秀/k/gim-Tae-hyeon] 作词 : 安英民 [作词 : ...
- Daily Scrum NO.5
工作概况 符美潇 昨日完成的工作 1.Daily Scrum.日常会议及日常工作的分配和查收. 2.变更集461代码签入,主要与视频链接爬取有关. 今日工作 1.Daily Scrum.日常会议及日常 ...
- 第四,五周——Java编写的电梯模拟系统(结对作业)
作业代码:https://coding.net/u/liyi175/p/Dianti/git 伙伴成员:石开洪 http://www.cnblogs.com/shikaihong/(博客) 这次的作业 ...
- 以webService为客户端获取List泛型结果集
首先搭建好webService,添加XFire1.2Core Libraries 和XFire1.2HTTP Client Libraries,连接上数据库,下例以oracle为数据库. 连接Oral ...
- (转)linux 内存管理——内核的shmall 和shmmax 参数
内核的 shmall 和 shmmax 参数 SHMMAX= 配置了最大的内存segment的大小 ------>这个设置的比SGA_MAX_SIZE大比较好. SHMMIN= 最小的内存seg ...
- flex与滚动冲突
如果设置方向用了flex,那么用滚动就没用
- nodejs nodemailer 使用
index.js const nodemailer=require("nodemailer") let sendEmail=function () { var transporte ...
- List元素删除不会导致越界但有问题的写法
今天在论坛里看到一段请教list删除的问题,下面先看代码: public static void main(String[] args) { List<Integer> list = ne ...
- ubuntu14.04如何设置静态IP的方法
第一步: 配置静态IP地址: 打开/etc/network/interfaces文件,内容为 auto lo iface lo inet loopback auto eth0 iface eth0 i ...