java基础-8-HashMap / concurrentHashMap

30 篇文章 0 订阅
4 篇文章 0 订阅

本片博客目的:记录hashMap的几个关键点,在知识点有些模糊的时候能够帮助我回忆

HashMap-

  1. 从结构出发: HashMap --------> Entry[]  --------> Entry{ next-->Entry , key-value , hash , id }
  2. PUT
    1. 先 hash(key.hashCode()) 找出要放到那一块Entry中,这里的hash位置是一个取模运算,但是使用位运算 &(length-1)来实现的,相比hashTable中的Math 取模 效率要高很多
    2. 要是Entry已经存在值了(HASH冲突),那就遍历检查Entry的key是否和传入值相等, 相等就说明是 修改旧值,全都不相等 那说明是增加新值 
    3. 这里还有知识点:要是这时候的存储量  >= capacity *loadFactor ,那要进行扩容,也就是reSize,这时候所有元素的存储地址entry要从新计算 ,非常消耗性能
  3. GET  的时候也是先计算 hash(key.hashCode()) 找 Entry位置,然后去entry中找 key的hash相同 || equal 返回true的值
  4. 在创建hashMap的时候要注意initcapacity的设置 ,不能太小防止内部多次扩容,也不能太大浪费内存占用
  5. hashMap 还要注意和hashTable不同,是线程不安全的,并发情况下,会出现Entry环,也就是在某一个Entry链出现了next指向自己的情况

 

ConcurrentHashMap-

1.7版本

  1. 内部的存储结构 ConcurrentHashMap-----> segment[]  segment---------HashEntry[]  HashEntry------->对应一个单向链表
  2. 使用了锁分离技术,能够实现并发操作,并且安全的原因是segment是一个AQS锁相关的实例,它的并发量concurrentLevel  就是segment[] 数组的长度,每一个线程能够拿到一个segment进入到lock阶段,当然不排除某一时刻所有操作都是在某一个segment里面,这个会出现操作时间过长的问题。
  3. 每一个segment里面是一个大table的数组格式,HashEntry[] ,这个就和HashMap非常相似,也是通过链式扩展来解决hash碰撞的问题
  4. PUT / GET :定位元素的第一步定位 segment ---> hash(key.hashCode()) 然后将 得到的hash值 进行一个 右偏移(将高位元素移到低位,然后高位元素制成0)和 segmentMask( ssize-1 :一般都是1111111这种格式) 取模然后又左偏移回高位,最后加上SBASE就是得到的segment的hash值了,这就简单的确定了第一个位置,接下来的位置确定同hashMap
  5. 扩容操作:segment[] 是不扩容的,扩容的是地下的table-HashEntry[] 翻倍,扩容规则也是和HashMap一样 >capacity*loadFactor
  6. size方法进行2次不加锁统计,结果一致就返回,不一致会进行枷锁然后重新计算size /  弱一致性:get的值可能不是最新的值

1.8版本

  1. 内部存储结构:变成了Node[] -----> node{hash, key, val, int next}
  2. 计算放在Node[]哪一个位置 : (h ^ (h >>> 16)) & HASH_BITS
  3. PUT 方法存放元素的并发安全实现是 通过 自旋 再加上cas的不断重试,以及某些情况加上synchronized来保证
  4. ....

更多的并发容器: concurrentSkipListMap /ConcurrentLinkedQueue

写时复制容器:CopyOnWriteArrayList /CopyOnWriteArraySet  使用场景:读多写少 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值