java集合的相关知识

HashMap源码解析1.8

new HashMap()创建一个空的map
put值时 resize() 初始化容量16 160.75=12(threshold) 超过12扩容,16<<1(162^1)=32, threshold=32*0.75=24
HashMap 允许 key 中有 一个null 值, HashTable 是不允许的,ConcurrentHashMap也是不允许的(无法分辨是key没找到的null还是有key值为null)。这样的好处就是可以给一个默认值

hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16) 异或
index = i = (n - 1) & hash 也就等于 hash % n(容量大小) 与

相比于put()方法,get()方法的实现就相对简单多了。主要分为两步,先是通过key的hash值计算目标bucket的下标,然后遍历对应bucket上的链表,逐个对比,得到结果

还是一样的存储套路,先根据key确定在哈希table中的下标,找到对应的bucket,遍历链表(或红黑树),做插入操作。在JDK7中,新增结点是使用头插法(引起死锁),但在JDK8中,在链表使用尾插法,将待新增结点追加到链表末尾

步骤①:若哈希table为null,或长度为0,则做一次扩容操作;
步骤②:根据index找到目标bucket后,若当前bucket上没有结点,那么直接新增一个结点,赋值给该bucket;
步骤③:若当前bucket上有链表,且头结点就匹配,那么直接做替换即可;
步骤④:若当前bucket上的是树结构,则转为红黑树的插入操作;
步骤⑤:若步骤①、②、③、④都不成立,则对链表做遍历操作。
a) 若链表中有结点匹配,则做value替换;
b)若没有结点匹配,则在链表末尾追加。同时,执行以下操作:
i) 若链表长度大于TREEIFY_THRESHOLD(8)(如果数组长度没有达到64,优先扩容解决),则执行红黑树转换操作;
ii) 若条件i) 不成立,则执行扩容resize()操作。
以上5步都执行完后,再看当前Map中存储的k-v对的数量是否超出了threshold,若超出,还需再次扩容。

当红黑树节点<UNTREEIFY_THRESHOLD(6),会缩容,转换为链表
resize()会重新hash,很耗时,尽量避免

ArrayList1.8

new ArrayList1()创建一个空的数组
add值时才扩容为10
每次扩容 int newCapacity = oldCapacity + (oldCapacity >> 1);就是乘1.5
然后copy数组到新数组:elementData = Arrays.copyOf(elementData, newCapacity);

HashSet

底层就是一个HashMap,元素不能重复

ConcurrentHashMap

table数组元素作为锁,从而实现了对每一行数据进行加锁,并发控制使用Synchronized和CAS来操作

多个线程又是如何同步处理的

在ConcurrentHashMap中,同步处理主要是通过Synchronized和unsafe两种方式来完成的。

·在取得sizeCtl、某个位置的Node的时候,使用的都是unsafe的方法,来达到并发安全的目的

·当需要在某个位置设置节点的时候,则会通过Synchronized的同步机制来锁定该位置的节点。

·在数组扩容的时候,则通过处理的步长和fwd节点来达到并发安全的目的,通过设置hash值为MOVED

·当把某个位置的节点复制到扩张后的table的时候,也通过Synchronized的同步机制来保证现程安全

从JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本中synchronized+CAS+HashEntry+红黑树,总结如下:
1、JDK1.7版本锁的粒度是基于Segment的,包含多个HashEntry,而JDK1.8实现降低锁的粒度就是HashEntry(首节点)
2、JDK1.8版本的数据结构变得更加简单,去掉了Segment这种数据结构,使用synchronized来进行同步锁粒度降低,所以不需要分段锁的概念,实现的复杂度也增加了
3、JDK1.8使用红黑树来优化链表,基于长度很长的链表的遍历是一个很漫长的过程,而红黑树的遍历效率是很快的,代替一定阈值的链表,这样形成一个最佳拍档

4、JDK1.8为什么使用内置锁synchronized来代替重入锁ReentrantLock:

  • 低粒度加锁方式,synchronized并不比ReentrantLock差,
    粗粒度加锁中ReentrantLock可能通过Condition来控制各个低粒度的边界,更加的灵活,而在低粒度中,Condition的优势就没有了
  • JVM的开发团队从来都没有放弃synchronized,而且基于JVM的synchronized优化空间更大,使用内嵌的关键字比使用API更加自然
  • 在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存
     ConcurrentHashMap 对单个Node加上同步锁
    在这里插入图片描述
    在这里插入图片描述
    ConcurrentHashMap 对单个Node加上同步锁

CopyOnWriteArrayList

使用写时复制策略保证list的一致性,而获取–修改–写入三个步骤不是原子性,所以需要一个独占锁保证修改数据时只有一个线程能够进行。另外,CopyOnWriteArrayList提供了弱一致性的迭代器,从而保证在获取迭代器后,其他线程对list的修改是不可见的,迭代器遍历的数组是一个快照。
CopyOnWriteArrayList

add(),remove()通过ReentrantLock加锁操作,获取当前Array,复制一份,再写入,写入完成,把新写入的数组设置为Array
get()不变,支持并发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值