一、HashMap 核心原理
1. 数据结构演进
-
JDK7:数组 + 链表
-
JDK8+:数组 + 链表 + 红黑树(桶长度≥8时转换)
2. 存取过程详解
put() 过程:
-
计算 key 的 hash:
(h = key.hashCode()) ^ (h >>> 16) -
计算桶下标:
(n-1) & hash -
处理冲突:
-
桶为空:直接插入
-
桶为链表:遍历比较(时间复杂度 O(n))
-
桶为红黑树:树插入(时间复杂度 O(log n))
-
-
检查扩容:size > threshold(容量×负载因子)
get() 过程:
-
同 put 方式计算桶位置
-
比较节点:
-
链表:顺序查找(最坏 O(n))
-
红黑树:树查找(最坏 O(log n))
-
二、红黑树深度解析
1. 为什么选择红黑树?
| 对比维度 | 链表 | 红黑树 | 完全二叉树 |
|---|---|---|---|
| 查询时间复杂度 | O(n) | O(log n) | O(log n) |
| 插入时间复杂度 | O(1) | O(log n) | O(log n) |
| 平衡要求 | 无 | 弱平衡 | 严格平衡 |
| 旋转操作频率 | 无 | 相对较少 | 频繁 |
| 内存占用 | 低 | 较高(2倍节点大小) | 与红黑树相当 |
选择原因:
-
折衷性能:相比 AVL 树减少旋转操作
-
稳定查询:最差情况比链表性能好
-
工程实践:JDK8 实测性能提升显著
2. 红黑树特性
-
节点是红或黑
-
根节点是黑色
-
红色节点的子节点必须为黑
-
从任一节点到其叶子的路径包含相同数量黑节点
-
新插入节点默认为红色
三、并发集合对比
1. HashTable vs ConcurrentHashMap
| 特性 | HashTable | ConcurrentHashMap (JDK8) |
|---|---|---|
| 锁粒度 | 全表锁 | 桶级别锁 + CAS |
| 并发性能 | 差 | 高 |
| Null 值支持 | 不允许 | 不允许 |
| 迭代器 | 强一致性 | 弱一致性 |
| 实现机制 | synchronized 方法 | CAS + synchronized 桶首节点 |
2. ConcurrentHashMap 优化
-
JDK7:分段锁(Segment)
-
JDK8:
-
桶首节点锁(synchronized)
-
CAS 无锁化操作
-
扩容协助机制
// JDK8 putVal 关键代码片段 if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value))) break; // CAS 成功插入 } else { synchronized (f) { // 锁住桶首节点 // 链表/树插入操作... } }
-
四、java.util.concurrent 包核心组件
1. 并发集合
-
ConcurrentHashMap:高并发 Map
-
CopyOnWriteArrayList:读多写少 List
-
ConcurrentSkipListMap:有序并发 Map
-
BlockingQueue 实现类:
-
ArrayBlockingQueue:数组阻塞队列
-
LinkedBlockingQueue:链表阻塞队列
-
PriorityBlockingQueue:优先级阻塞队列
-
2. 原子类
-
基本类型:AtomicInteger, AtomicLong
-
引用类型:AtomicReference
-
数组:AtomicIntegerArray
-
字段更新:AtomicIntegerFieldUpdater
3. 线程工具
| 类名 | 用途 |
|---|---|
| CountDownLatch | 多线程同步计数器 |
| CyclicBarrier | 可重复使用的栅栏 |
| Semaphore | 信号量控制资源访问 |
| Phaser | 更灵活的阶段同步器 |
| CompletableFuture | 异步编程组合操作 |
4. 锁机制
-
ReentrantLock:可重入锁(替代 synchronized)
-
ReentrantReadWriteLock:读写分离锁
-
StampedLock:乐观读锁(JDK8+)
五、高频问题示例
Q1:HashMap 多线程死循环问题?
-
JDK7:头插法扩容导致链表逆序,可能产生环形链
-
JDK8:改为尾插法解决,但仍有数据覆盖问题
Q2:ConcurrentHashMap size() 的准确性?
-
JDK8 使用 baseCount + CounterCell[] 分片计数
-
最终结果是近似值(弱一致性)
Q3:为什么红黑树退化阈值为6?
-
避免频繁树化和退化(设置8和6的缓冲区间)
-
防止哈希碰撞攻击时性能波动
Q4:ConcurrentHashMap 读操作需要加锁吗?
-
不需要,通过 volatile 和 Unsafe 保证可见性
-
读操作完全无锁,性能极高
理解这些原理需要结合实际编码经验,建议通过源码分析和性能测试加深理解。对于高级开发者,建议研究:
-
HashMap 在分布式场景下的变种(如一致性哈希)
-
自定义并发容器的设计思路
-
JUC 工具类在复杂业务中的组合应用
本文详细介绍Android应用发布前的准备工作,包括代码混淆、第三方加密、分渠道打包等关键步骤,并介绍了如何利用Gradle进行多渠道打包,提高应用市场投放效率。

129

被折叠的 条评论
为什么被折叠?



