【面试官】HashMap为什么线程不安全?

  • 面试官:你说下HashMap的内部结构?
  • 面试官:那一个键值是怎么存储到HashMap的?
  • 面试官:HashMap链表还会转换成什么?
  • 面试官:HashMap为什么线程不安全?
  • 面试官:有线程安全的Map吗?
  • 面试官:HashTable和ConcurrentHashMap有什么区别吗?

大家好,我是南哥。

一个Java学习与进阶的领路人,跟着南哥我们一起Java成长。

文章目录

  1. HashMap内部结构
    1. 键值的添加流程
    2. 红黑树
  2. 线程安全的Map
    1. 线程不安全的HashMap
    2. 线程安全的ConcurrentHashMap
    3. HashTable和ConcurrentHashMap

1. HashMap内部结构

面试官:你说下HashMap的内部结构?

好的面试官。

HashMap内部存储数据的对象是一个实现Entry接口的Node数组,也称为哈希桶transient Node<K,V>[] table,后面我们称Node数组为Entry数组。Entry数组初始的大小是16

Node节点的内部属性key、value分别代表键和值,hash代表key的hash值,而next则是指向下一个链表节点的指针。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

1.1 键值的添加流程

面试官:那一个键值是怎么存储到HashMap的?

首先会调用hash方法计算key的hash值,通过key的hashCode值与key的hashCode高16位进行异或运算,使hash值更加随机与均匀。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

再通过该hash值与Entry数组的长度相与,得到要存储到的索引位置int index = (table.length - 1) & hash。如果该索引位置是空的,会把键值直接添加到表头,如果哈希冲突了则会用链表法形成一条链表。

数据添加后,会判断当前容量是否到达了threshold阈值,threshold等于负载因子loadFactor * table.length。负载因子默认是0.75,threshold第一次扩容时为0.75 * 16 = 12

如果到达阈值了则会对Entry数组进行扩容,扩容成为原来两倍容量的Entry数组。

1.2 红黑树

面试官:HashMap链表还会转换成什么?

当链表长度 >= 8时,会把链表转换为红黑树

是这样的,HashMap的链表元素如果数量过多,查询效率会越来越低,所以需要将链表转换为其他数据结构。而二叉搜索树这种数据结构是绝对的子树平衡,左节点比父节点小,右节点比父节点大,在极端情况会退化为链表结构

而红黑树放弃了绝对的子树平衡,转而追求的是一种大致平衡,在极端情况下的数据查询效率更优。

static final class TreeNode<K,V> exten

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试突击 文章被收录于专栏

👉以面试官面试的形式,涵盖了你怒怼大厂面试官、拿下大厂面试所需掌握的核心知识、面试重点! 👉相信一定对你顺利通关面试、拿到理想Offer有所帮助! 👉花费大量精力去制作本专栏,创作不易,各位的支持就是我创作的最大动力!

全部评论

相关推荐

10-17 10:05
已编辑
北华大学 全栈开发
牛客872465272号:掉头发了哥
点赞 评论 收藏
分享
SinyWu:七院电话面的时候问我有没有女朋友,一听异地说你赶紧分。我:???
点赞 评论 收藏
分享
4 7 评论
分享
牛客网
牛客企业服务