主题
面试速答(先看这里)
**一句话结论:**这个问题挺有意思的,如果真要对比,可以列出几十条的区别来,因为毕竟他们俩差异太大了, 一个是Redis中的,一个是Java中的,虽然都是hash结构。
60秒标准回答:
这个问题挺有意思的,如果真要对比,可以列出几十条的区别来,因为毕竟他们俩差异太大了, 一个是Redis中的,一个是Java中的,虽然都是hash结构。如果面试官问这个问题的话,我认为他可能比较关注的是这几个区别
1、底层数据结构
2、并发安全相关
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **要点1:**Redis的hash结构底层是基于ziplist(压缩列表)和hashtable实现的(6.0中ziplist改为了listpack)。
- **要点2:**ziplist用于小的hash结构,而hashtable用于大的hash结构,和zset差不多,也是可以通过配置来调整具体使用的结构的,以下两个同时满足时用ziplist,否则用hashtable。
- **要点3:**而Java中的HashMap本身并不是线程安全的,需要用使用ConcurrentHashMap来保证线程安全。
- **要点4:**Redis的hash结构在扩容的时候,采用一种渐进式rehash的方案,可以实现平滑扩容,避免一次性迁移所有数据导致的请求延迟。
- **要点5:**Java中的HashMap是没有采用渐进式rehash的,而是会一次性完成整个 Map 中所有元素的迁移。
**记忆锚点:**HashMap → Redis → hash → ziplist → hashtable → rehash
关键取舍:
- Hash 中 k-v 对的数量 <= hash-max-ziplist-entries (默认 512) 所有 k 和 v 的字符串长度 <= hash-max-ziplist-value (默认 64 字节) ziplist/listpack的优点是极其节省内存。
- hashtable的优点是查找、插入、删除的平均时间复杂度 O(1),适合大数据量。
- 好处和缺点刚好和上面的渐进式rehash相反,优点是不占用过多空间,缺点就是迁移过程会阻塞。
易错提醒:
- ( Collections.synchronizedMap(new HashMap<>()) 也可以) Redis的hash结构在扩容的时候,采用一种渐进式rehash的方案,可以实现平滑扩容,避免一次性迁移所有数据导致的请求延迟。
加分表达:
- 这个问题挺有意思的,如果真要对比,可以列出几十条的区别来,因为毕竟他们俩差异太大了, 一个是Redis中的,一个是Java中的,虽然都是hash结构。
- 如果面试官问这个问题的话,我认为他可能比较关注的是这几个区别: 1、底层数据结构 2、并发安全相关 Redis的hash结构底层是基于ziplist(压缩列表)和hashtable实现的(6.0中ziplist改为了listpack)。
- ziplist用于小的hash结构,而hashtable用于大的hash结构,和zset差不多,也是可以通过配置来调整具体使用的结构的,以下两个同时满足时用ziplist,否则用hashtable。
追问准备:
- 围绕「HashMap」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「Redis」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「hash」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
典型回答
这个问题挺有意思的,如果真要对比,可以列出几十条的区别来,因为毕竟他们俩差异太大了, 一个是Redis中的,一个是Java中的,虽然都是hash结构。如果面试官问这个问题的话,我认为他可能比较关注的是这几个区别:
1、底层数据结构
2、并发安全相关
3、扩容机制
数据结构
Redis的hash结构底层是基于ziplist(压缩列表)和hashtable实现的(6.0中ziplist改为了listpack)。
ziplist用于小的hash结构,而hashtable用于大的hash结构,和zset差不多,也是可以通过配置来调整具体使用的结构的,以下两个同时满足时用ziplist,否则用hashtable。
- Hash 中
k-v对的数量 <=hash-max-ziplist-entries(默认 512) - 所有 k 和 v 的字符串长度 <=
hash-max-ziplist-value(默认 64 字节)
📄 ✅Redis的ZipList、SkipList和ListPack之间有什么区别?
打开文档:✅Redis的ZipList、SkipList和ListPack之间有什么区别?
ziplist/listpack的优点是极其节省内存。没有指针开销,内存局部性好。但是缺点就是增删改查操作(尤其是中间插入/删除)时间复杂度 O(n),效率较低。
hashtable的优点是查找、插入、删除的平均时间复杂度 O(1),适合大数据量。缺点就是内存开销较大,需要额外存储指针。
📄 ✅ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList?
打开文档:✅ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList?
而HashMap采用的是数组+链表+红黑树的存储结构。
并发安全
因为Redis本身是单线程执行命令的,所以所有对 Redis Hash 的操作都是线程安全的。
而Java中的HashMap本身并不是线程安全的,需要用使用ConcurrentHashMap来保证线程安全。(Collections.synchronizedMap(new HashMap<>())也可以)
扩容机制
Redis的hash结构在扩容的时候,采用一种渐进式rehash的方案,可以实现平滑扩容,避免一次性迁移所有数据导致的请求延迟。但是缺点就是在数据迁移期间,内存占用是翻倍的。
Java中的HashMap是没有采用渐进式rehash的,而是会一次性完成整个 Map 中所有元素的迁移。好处和缺点刚好和上面的渐进式rehash相反,优点是不占用过多空间,缺点就是迁移过程会阻塞。
但是其实HashMap也没必要搞渐进式rehash,因为HashMap一般都是存很少的数据,不像Redis一样大家会拿他来存很多东西。