Java基础-Map

Map集合是双列集合,就是说它存储的都是键值对(K-V)。

HashMap

介绍

HashMap是Map下最常用的集合类。对K进行hash运算,得到hashcode,从而存储元素。然而,hash算法不是完美算法,只能尽可能对键值进行散列,的到元素在内存中的存储位置。所以会产生hash冲突。解决hash冲突的方法有开放地址发、再散列法,链表法。

在jdk1.7中HashMap底层采用数组+链表存储数据。数组中的每个位置对应一个hashcode,进行hash运算时,将元素映射到数组指定位置。当发生冲突时,将元素形成单链表存储在数组原本位置。所以HashMap最好情况(全部散列均匀没有形成链表)的时间复杂度为O(1)
最坏情况(元素全部被散列到数组同一位置,形成一条链表)的时间复杂度O(n)

在jdk1.8中HashMap底层采用数组+链表+红黑树实现。由于单链表遍历的时间复杂度比较大。所以在1.8中采用红黑树(一种高度平衡的二叉树)。这样遍历产生冲突的元素时间复杂度就会变成O(lgN)
那么何时单链表会转化为红黑树呢

下面是jdk1.8中HashMap的源码
下图中的TREEIFY_THRESHOLD是转化为红黑树的节点数量的阈值8
UNTREEIFY_THRESHOLD = 6是红黑树转化为单链表的节点数量阈值
在这里插入图片描述
这是put方法的实现,在643行,检查节点数量,如果大于等于7则调用转化红黑树的方法treeifyBin。(这里的TREEIFY_SHOLD为什么会减一。这是因为先向单链表中添加节点后,再检查节点数量)
在这里插入图片描述
为何会选用6和8
这是因为当节点数量为6时,单链表和红黑树遍历的时间复杂度都为3,当节点数量大于6时,红黑树遍历的时间复杂度才比单链表低,所以小于6时使用单链表存储。因为单链表和红黑树的转变会消耗很多的时间和空间,当特殊情况时,节点数量在6和7不断徘徊,会造成内存极大的浪费。

TreeMap

TreeMap也是很常用的结构,以为它是一个排序的二叉树,会对key进行排序(从小到大),如果想要自定义排序需要重写compare方法。底层实现是红黑树。

Hashtable

Hashtable是线程安全的,在各个方法上加了synchronized关键字。和HashMap类似。现在不推荐使用Hashtable,因为有专门在多线程环境下的ConcurrentHashMap

ConcurrentHashMap

jdk1.7
在jdk1.7中采用Segment分段锁+HashEntry机制。一个HashMap中有一个Segment数组(初始容量为16),每个Segment对象有一个HashEntry数组。对每个Segment对象分别加锁。这样当进行同步操作时只会锁住一部分,大大提高了效率。
在操作时会先进行hash定位到Segment,然后在进行hash,定位到HashEntry的元素。

在进行get操作时,是不需要加锁的,那如何保证get到的数据是最新的。原来HashEntry中的value使用volatile修饰,保证各线程可见。

size操作时,会计算元素的个数,而这个操作时并发的。在计算元素个数时仍然在插入数据。所以ConcurrentHashMap会进行多次统计,至多3次,比较每次统计的数量是否一样。如果一样就认为数据是准确的。否则会给Segment加锁在统计一次。

jdk1.8
在jdk1.8中放弃了Segment设计,采用CAS+Synchronized的设计(jdk对Synchronized进行了优化,提升了性能),底层采用数组+链表+红黑树实现。

何谓CAS:即比较和交换(compage and swap),是一种乐观锁的实现。悲观锁是将整个资源锁住,等之前获得锁的线程执行完毕释放锁后,其他等待的线程才得以执行。乐观锁是采取不加锁的方式,通过数据version控制正确的读写。
CAS有三个值:内存值、期望值、新值。当一个线程执行时,只有当期望值等于内存值,才会将新值覆盖原来的内存值。如果不是,则等待下一次循环继续执行,直到成功。

好处

  1. 降低了锁的粒度,jdk1.7中锁的粒度是Segment,而1.8中是每个HashEntry节点
  2. Synchronized优化了,效率提高。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值