一、 集合框架的深层源码剖析

难度:中等 | 类型:原理分析

1. HashMap 的“树化”与“退化”机制

· 核心原理:当链表长度 \ge 8 且数组长度 \ge 64 时,链表转为红黑树(时间复杂度由 O(n) 优化为 O(\log n))。
· 边界条件:当红黑树节点因删除操作减少至 \le 6 时,会退化为链表,以维护结构性能。
· 代码演示:自定义对象作为 Key 时,必须重写 hashCode() 和 equals() 方法,否则会导致内存泄漏(数据无法被再次找到)。

2. ArrayList 的扩容机制

· 关键点:ArrayList 本质是数组,无参构造初始化容量为 0(JDK1.8 后懒加载),第一次 add 时扩容至 10。
· 源码逻辑:每次扩容为原容量的 1.5 倍(oldCapacity >> 1),通过 Arrays.copyOf 进行底层数组复制,属于重成本操作。
· 最佳实践:若已知数据量较大(如从数据库导出万级数据),应在初始化时指定容量(new ArrayList<>(10000)),避免频繁扩容带来的性能开销。

---

二、 并发编程的进阶应用

难度:中等 | 类型:编码实战

1. CompletableFuture 异步编排

· 业务场景:在电商首页,需要并行调用【用户信息】、【库存系统】、【推荐列表】三个接口,全部完成后汇总数据。
· 陷阱规避:异步编程中异常会“静默”吞掉,必须显式处理。
· 实现代码:
  ```java
  // 模拟三个异步任务
  CompletableFuture<String> userInfo = CompletableFuture.supplyAsync(() -> getUser());
  CompletableFuture<String> stockInfo = CompletableFuture.supplyAsync(() -> getStock());
  
  // allOf 等待所有任务完成,join 防止主线程过早结束
  CompletableFuture<Void> all = CompletableFuture.allOf(userInfo, stockInfo);
  all.thenRun(() -> {
      // 所有任务执行完毕后的回调
      System.out.println(userInfo.join() + stockInfo.join());
  }).exceptionally(ex -> {
      log.error("异步执行出错", ex); // 必须捕获异常,否则业务无感知
      return null;
  });
  ```

2. 锁的优化策略

· 场景:使用 synchronized 锁住“读多写少”的字典数据会导致性能瓶颈。
· 优化:使用 ReadWriteLock(读写锁)或 StampedLock 实现读写互斥,读读并发,显著提高吞吐量。
· 细粒度锁:在秒杀扣减库存时,不应锁整个方法,而是对具体的商品 ID 加锁(如 ConcurrentHashMap 配合 computeIfAbsent)。

---

三、 SQL 索引优化实战

难度:中等 | 类型:数据库调优

1. 索引失效的典型场景
很多开发者写了 SQL 却发现查询依然慢,通常是因为索引没有被正确使用:

错误写法 后果 正确姿势
where name like '%张三' 索引完全失效(带头摇摆) 改为 '张三%' 或使用搜索引擎
where date(create_time) = '2024-01-01' 对索引字段做了函数计算 改为 create_time between '2024-01-01' and '2024-01-02'
where a = 1 or b = 2 (非复合索引) 可能不走索引(全表扫描) 拆分为两个查询或使用 union
where status = 1 (status 只有0,1) 回表代价过高,优化器放弃索引 若数据倾斜严重,考虑强制索引或过滤

2. 深分页问题解决

· 痛点:limit 100000, 10 会扫描前 10 万条数据并丢弃,效率极低。
· 解决方案:使用 “延迟关联” 或 “书签记录”。
  ```sql
  -- 低效
  SELECT * FROM orders ORDER BY id LIMIT 100000, 10;
  
  -- 高效 (覆盖索引 + 延迟关联)
  SELECT * FROM orders t1 
  JOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 10) t2 
  ON t1.id = t2.id;
  ```

---

四、 内存分析与 JVM 调优基础

难度:中等 | 类型:故障排查

1. 定位内存泄漏

· 现象:服务器运行一段时间后,CPU 飙升或频繁 Full GC。
· 排查工具:使用 jmap 导出堆转储文件(Heap Dump),利用 Eclipse MAT 分析工具找出占用内存最大的对象(Dominator Tree)。
· 常见根源:
  · ThreadLocal 使用后未调用 remove()(尤其在 Tomcat 线程池环境中,导致线程复用后数据残留)。
  · 数据库查询一次性读取了全表几十万条数据到 List 中。

2. GC 选型参考

· 追求低延迟(如实时交易系统):选择 G1 或 ZGC(JDK 11+),避免“Stop-The-World”时间过长。
· 追求高吞吐(如后台批处理系统):选择 Parallel Scavenge,充分利用 CPU 资源进行计算。

---

五、 避免空指针的防御式编程

难度:中等 | 类型:代码规范

1. Optional 妙用
不仅用于返回值,还可以用于连续判断。

```java
// 噩梦级代码
if (user != null) {
    Address addr = user.getAddress();
    if (addr != null) {
        String city = addr.getCity();
        // ...
    }
}

 

更多推荐