Java 集合框架与数据结构核心速记笔记

0 阅读5分钟

核心总览:本笔记系统梳理了 Java 集合框架及线性数据结构的底层原理、并发控制、性能特征与适用场景。核心法则是:单线程重性能,高并发重安全,读多写少用并发,排序有序选树链。


一、List 接口实现类(有序可重复)

集合类底层结构线程安全核心特性与适用场景典型实战用法
ArrayList数组查询极快 (O(1)) ,增删慢 (O(n))。适合查询多、增删少的单线程场景。数据库批量查询结果遍历展示;预分配容量 new ArrayList<>(1000) 避免频繁扩容。
LinkedList双向链表头尾增删快 (O(1)) ,查询慢 (O(n))。适合频繁两端操作。实现队列/栈(但推荐用 ArrayDeque);严禁用 get(i) 做随机访问
CopyOnWriteArrayList数组(写时复制)读无锁,写复制整个数组。适合读多写少的并发场景。事件监听器列表(如 Dubbo 服务通知、ZooKeeper Watcher);避免频繁写或大列表写
Vector数组是(过时)方法全 synchronized,性能差。基本淘汰,仅用于兼容老旧遗留系统。

二、Map 接口实现类(键值对映射)

集合类底层结构线程安全核心特性与适用场景典型实战用法
HashMap数组+链表/红黑树存取基本 O(1),允许 null 键/值。最通用的 Map。单线程下的键值缓存、映射关系存储;高并发下会导致环形链表或数据丢失
ConcurrentHashMap数组+链表/红黑树高并发首选。JDK 8 用 CAS + synchronized 锁桶头,吞吐量极高。微服务注册中心缓存元数据、管理连接;Key/Value 均不允许为 null
Hashtable数组+链表是(过时)方法全 synchronized,全局一把锁,并发性能极差。已淘汰,用 ConcurrentHashMap 替代。
LinkedHashMap哈希表+双向链表维护插入顺序访问顺序实现 LRU 缓存(重写 removeEldestEntry),如 MyBatis 缓存。
TreeMap红黑树按 Key 自然排序或定制排序,查找 O(log n)。排行榜、区间查询(如按时间戳查日志 subMap)。
WeakHashMap哈希表Key 为弱引用,GC 时自动回收。监听器注册表,防止内存泄漏(外部引用消失,Map 自动清理)。
IdentityHashMap数组(线性探测)== 而非 equals 判断 Key 相等。AOP 代理对象映射、目标对象追踪(如 Spring 内部实现)。

三、Set 接口实现类(去重)

Set 内部依赖 Map 实现,利用 Key 不可重复特性。

  • HashSet:基于 HashMap,存取 O(1),不保序。用于常规去重(如标签、ID)。
  • LinkedHashSet:基于 LinkedHashMap,维护插入顺序。
  • TreeSet:基于 TreeMap,支持自然排序或定制排序。

四、队列与栈

类别推荐实现核心特性典型场景
双端队列(栈/队列)ArrayDeque数组实现,比 LinkedList 和 Stack 更快更省内存。JVM 方法调用栈、线程池任务队列。
无锁并发队列ConcurrentLinkedQueue无锁高吞吐。高并发生产者-消费者模型。
有界阻塞队列ArrayBlockingQueue满时阻塞生产者,空时阻塞消费者。资源池、任务队列(如 Tomcat 工作线程),防内存溢出
无界阻塞队列LinkedBlockingQueue吞吐量高于 Array,默认容量极大。Executors.newFixedThreadPool 的底层队列。
直接交接队列SynchronousQueue不存储元素,生产者必须等消费者接收。Executors.newCachedThreadPool,任务即时处理。
延迟队列DelayQueue元素到期才能取出。定时任务调度、订单超时关闭。
优先级队列PriorityBlockingQueue按优先级出队(堆实现)。优先级消息处理。

五、基础数据结构对比

维度数组 (如 ArrayList)链表 (如 LinkedList)
内存布局连续内存,大小固定分散内存,靠指针相连
访问效率随机访问 O(1)随机访问 O(n),需遍历
增删效率中间增删 O(n),需挪动数据增删 O(1) (前提是已定位到位置)
空间开销仅存数据,内存紧凑需存前后指针,开销较大

六、核心原理与底层机制

1. HashMap 核心机制

  • 定位桶(n - 1) & hash(容量必为 2 的幂,位运算替代取模,极速)。
  • 树化机制:链表长度 > 8 数组长度 >= 64 时,链表转红黑树(查找从 O(n) 提升到 O(log n));树节点 < 6 时退回链表。
  • 扩容机制:默认容量 16,负载因子 0.75(size > 16*0.75=12 时触发),扩容为原 2 倍,需重新计算所有元素位置。
  • 性能优化:预估数据量时指定初始容量(如存 1000 个元素,设 new HashMap<>(2048)),避免频繁扩容。

2. 线程安全与并发控制

  • ConcurrentHashMap (JDK 8+) :摒弃 Segment,采用 CAS + synchronized,仅锁链表/红黑树头节点,并发度极高;读操作无锁(靠 volatile 保证可见性)。

  • CopyOnWriteArrayList:写操作加锁并复制整个数组,读操作无锁;缺点:写代价高,内存占用大,数据弱一致性。

3. Fail-Fast 机制

  • 集合内部维护 modCount,遍历期间若结构被修改,迭代器比对发现不一致则抛出 ConcurrentModificationException
  • 安全删除:遍历时删除必须用 iterator.remove(),或直接使用并发容器。

七、实战避坑指南(⭐ 重点牢记)

  1. ArrayList 必预分配:已知大小时 new ArrayList<>(capacity),避免多次 1.5 倍扩容和数组拷贝。
  2. 禁用 LinkedList 的 get(i) :链表随机访问是 O(n),性能极差。
  3. CopyOnWriteArrayList 忌频繁写:写操作全量复制,大列表或高频写场景会拖垮性能。
  4. 遍历时安全删除:严禁 list.remove(obj),必须用迭代器的 remove()
  5. HashMap 忌并发写:多线程 put 会导致环形链表和数据丢失,务必用 ConcurrentHashMap。
  6. 重写 equals 必重写 hashCode:否则 HashMap/HashSet 中逻辑相同的对象会被当成两个 Key,导致存取失败。
  7. ConcurrentHashMap 不允许 null:Key/Value 均不能为 null,避免 containsKeyget 歧义。
  8. 别用过时类:Stack(用 ArrayDeque)、Hashtable(用 ConcurrentHashMap)、Vector(用 CopyOnWriteArrayList)。
  9. HashMap 容量设 2 的幂:保证 hash & (n-1) 等效取模且分布均匀,减少哈希冲突。