JAVA面试提纲之-HashMap与ConcurrentHashMap

不是完整详细的介绍,只是一个精简版的思路或提纲,在面试时被问到可以在理解的基础上顺着本提纲展开扩充。

简单介绍 HashMap。
  1. JAVA非常经典的结构,常用于在内存中存放数据;
  2. 1.7之前底层是基于 数组 + 链表 组成的;
  3. 给定的默认容量为 16,负载因子为 0.75。Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。
  4. put操作:判断当前数组是否需要初始化;如果 key 为空,则 put 一个空值进去;根据 key 计算出 hashcode;根据计算出的 hashcode 定位出所在桶;如果桶是一个链表则需要遍历判断里面的 hashcode、key 是否和传入 key 相等,如果相等则进行覆盖,并返回原来的值;如果桶是空的,说明当前位置没有数据存入;新增一个 Entry 对象写入当前位置。
1.8 做了哪些优化?
  1. 1.7中当 Hash 冲突严重时,在桶上形成的链表会变的越来越长,这样在查询时的效率就会越来越低;时间复杂度为 O(N);
  2. 所以引入了红黑树;put时判断当前链表的大小是否大于预设的阈值,大于时就要转换为红黑树。
有哪些线程安全方面的问题?

HashMap 扩容的时候会调用 resize() 方法,就是这里的并发操作容易在一个桶上形成环形链表;这样当获取一个不存在的 key 时,计算出的 index 正好是环形链表的下标就会出现死循环。

介绍一下ConcurrentHashMap

1.7中:

  1. ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock;
  2. HashEntry 中的 value 使用 volatile 关键词修饰的,但是并不能保证并发的原子性,所以 put 操作时仍然需要加锁。
  3. get时Key 通过 Hash 之后定位到具体的 Segment ,再通过一次 Hash 定位到具体的元素上。
  4. 并发时只在当前segment上上锁,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

1.8中:

  1. 使用CAS加synchronized代替ReentrantLock,不再使用Segment;
  2. 存储使用了红黑树;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值