【Java面试八股文宝典之基础篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day12

2023-02-24 13:19:34 浏览数 (2)

谈谈Concurrent(可考润s)HashMap的扩容机制

1.7版本

1. 1.7版本的ConcurrentHashMap是基于Segment(色们)分段实现的

2. 每个Segment相对于⼀个⼩型的HashMap

3. 每个Segment内部会进⾏扩容,和HashMap的扩容逻辑类似

4. 先⽣成新的数组,然后转移元素到新数组中

5. 扩容的判断也是每个Segment内部单独判断的,判断是否超过阈值

1.8版本

1. 1.8版本的ConcurrentHashMap不再基于Segment实现

2. 当某个线程进⾏put时,如果发现ConcurrentHashMap正在进⾏扩容那么该线程⼀起进⾏扩容

3. 如果某个线程put时,发现没有正在进⾏扩容,则将key-value添加到ConcurrentHashMap中,然

后判断是否超过阈值,超过了则进⾏扩容

4. ConcurrentHashMap是⽀持多个线程同时扩容的

5. 扩容之前也先⽣成⼀个新的数组

6. 在转移元素时,先将原数组分组,将每组分给不同的线程来进⾏元素的转移,每个线程负责⼀组

或多组的元素转移⼯作

Jdk1.7到Jdk1.8 HashMap 发⽣了什么变化(底层)?

1. 1.7中底层是数组 链表,1.8中底层是数组 链表 红⿊树,加红⿊树的⽬的是提⾼HashMap插⼊

和查询整体效率

2. 1.7中链表插⼊使⽤的是头插法,1.8中链表插⼊使⽤的是尾插法,因为1.8中插⼊key和value时

需要判断链表元素个数,所以需要遍历链表统计链表元素个数,所以正好就直接使⽤尾插法

3. 1.7中哈希算法⽐较复杂,存在各种右移与异或运算,1.8中进⾏了简化,因为复杂的哈希算法的

⽬的就是提⾼散列性,来提供HashMap的整体效率,⽽1.8中新增了红⿊树,所以可以适当的简化

哈希算法,节省CPU资源

说⼀下HashMap的Put⽅法

先说HashMap的Put⽅法的⼤体流程:

1. 根据Key通过哈希算法与与运算得出数组下标

2. 如果数组下标位置元素为空,则将key和value封装为Entry对象(

JDK1.7中是Entry对象,JDK1.8中是Node对象)并放⼊该位置

3. 如果数组下标位置元素不为空,则要分情况讨论

a. 如果是JDK1.7,则先判断是否需要扩容,如果要扩容就进⾏扩容,如果不⽤扩容就⽣成Entry

对象,并使⽤头插法添加到当前位置的链表中

b. 如果是JDK1.8,则会先判断当前位置上的Node的类型,看是红⿊树Node,还是链表Node

ⅰ. 如果是红⿊树Node,则将key和value封装为⼀个红⿊树节点并添加到红⿊树中去,在这个

过程中会判断红⿊树中是否存在当前key,如果存在则更新value

ⅱ. 如果此位置上的Node对象是链表节点,则将key和value封装为⼀个链表Node并通过尾插

法插⼊到链表的最后位置去,因为是尾插法,所以需要遍历链表,在遍历链表的过程中会

判断是否存在当前key,如果存在则更新value,当遍历完链表后,将新链表Node插⼊到链

表中,插⼊到链表后,会看当前链表的节点个数,如果⼤于等于8,那么则会将该链表转

成红⿊树

ⅲ. 将key和value封装为Node插⼊到链表或红⿊树中后,再判断是否需要进⾏扩容,如果需要

就扩容,如果不需要就结束PUT⽅法

0 人点赞