HashMap(1.7、1.8对比)、Hashtable、ConcurrentHashMap(1.7、1.8)

1.HashMap(线程不安全,多线程同时对其操作时会产生线程安全问题)

HashMap基于Map接口,是一种基于Key-Value的数据结构,允许有一个key为null,多个value为null。

HashMap的默认数组长度为16,扩容因子为0.75,每次扩容成2的n次方数值,也就是扩容两倍,默认第一次扩容阈值16*0.75=12

HashMap的实现原理:
jdk1.7
采用数组+链表实现
插入时头插
jdk1.8
采用数组+链表+红黑树实现
插入时尾插(避免老版本hashmap在并发resize时会出现的死循环问题)
当链表长度大于等于8时会转换成红黑树,而当链表长度小于等于6时会退化成链表

2.Hashtable(线程安全,对整个结构加锁,性能不好)
同样为Key-Value数据结构,但不允许key,value的值为null
默认数组长度为11
实现原理:数组+链表

3.ConcurrentHashMap(线程安全)
image-20200727163100466
总结问题:

1.为什么将某些类对象放入HashMap一定要重写HashCode方法和equals()方法?
答:这就和HashMap的底层实现原理有关,将对象放入HashMap,首先会判断传入键的hash值是否相同,如果不同则直接放入集合中,如果相同,则进一步进行equals判断,如果equals判断也相同,那么后来传入的键会将前面的键覆盖。
2.ConcurrentHashMap和HashTable有什么区别?能否取代HashMap?
答:主要区别体现在实现线程安全的方式上
①在jdk1.7时,ConcurrentHashMap采用分段锁方式对整个桶数组进行了分割分段(Segment),每一把锁只锁容器中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提供了并发访问率;
到了jdk1.8,直接摒弃了Segment的概念,直接采用Node数组+链表+红黑树来实现,并发控制使用synchronized和CAS来操作。
②Hashtable则直接对整个结构加锁(synchronized)来保证线程安全,效率非常低下。当一个线程访问同步方法时,其它线程也访问同步方法,可能会进入阻塞或轮询状态,如果使用put添加元素,另一个线程就不能使用put添加元素,也不能使用get。
③不能取代HashMap,Hashtable的任何操作都会把表锁住,是阻塞的,好处是总能够获取最实时的更新,ConcurrentHashMap为非阻塞的,在更新时会局部锁住某部分数据,但不会把整个表都锁住,同步读取操作是完全非阻塞的,在合理条件下效率非常高,坏处是在大量的读取操作时不能保证数据的实时更新。
3.HashMap的长度为什么是2的倍数?
在HashMap的操作流程中,首先会对key进行hash算法得到一个索引值,这个索引值就是对应哈希桶数组的索引。为了得到这个索引值必须对扰动后的数跟数组长度进行取余运算。即 hash % n (n为hashmap的长度),又因为&比%运算快。n如果为2的倍数,就可以将%转换为&,结果就是 hash & (n-1)。所以这就解释了为什么HashMap长度是2的倍数。
4.HashMap底层是如何实现的?
首先底层数据结构是由数组+链表组成链表散列。HashMap先得到key的散列值,在通过扰动函数(减少碰撞次数)得到Hash值,接着通过hash & (n -1 ),n为table的长度,运算后得到数组的索引值。如果当前节点存在元素,则通过比较hash值和key值是否相等,相等则替换,不相等则通过拉链法查找元素,直到找到相等或者下个节点为null时。
1.8对扰动函数,扩容方法进行优化,并且增加了红黑树的数据结构。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值