java8的集合和map

Java 8 集合与 Map 全览及原理

一、整体架构

                    Iterable
                      │
                    Collection                    Map
                   ╱    │    ╲                  ╱    ╲
                List  Set  Queue          SortedMap  ...
               ╱  ╲    │      ╲            │
          ArrayList  LinkedList  TreeSet  TreeMap
          Vector     HashSet     PriorityQueue
          Stack      LinkedHashSet
                    (CopyOnWriteArraySet)

二、List 系列(有序、可重复)

1. ArrayList

  • 底层数据结构Object[] 数组
  • 原理
    • 默认初始容量 10,按 1.5 倍扩容(oldCapacity + (oldCapacity >> 1)
    • 随机访问 get(i) 时间复杂度 O(1),通过数组下标直接定位
    • 头部插入/删除需要移动元素,O(n)
    • 尾部插入均摊 O(1)
    • 非线程安全

2. Vector

  • 底层数据结构Object[] 数组
  • 原理:与 ArrayList 几乎相同,区别在于:
    • 所有公共方法加 synchronized线程安全但性能差
    • 扩容默认 2 倍(可自定义增长系数)
    • 现已基本不使用,被 Collections.synchronizedList()CopyOnWriteArrayList 替代

3. Stack

  • 底层数据结构:继承自 Vector 的数组
  • 原理
    • LIFO(后进先出)栈结构
    • push() 尾部入栈,pop() 尾部出栈
    • 同样加 synchronized,线程安全但性能差
    • 官方推荐使用 Deque(如 ArrayDeque)替代

4. LinkedList

  • 底层数据结构双向链表
  • 原理
    • 每个节点保存 prevnext 两个指针
    • 随机访问需要从头/尾遍历,O(n)
    • 头尾插入/删除 O(1)(已知节点位置时)
    • 同时实现了 ListDeque 接口,可作为链表、队列、栈使用
    • 非线程安全

三、Set 系列(无序、不可重复)

1. HashSet

  • 底层数据结构HashMap<E, Object>
  • 原理
    • 内部用一个 HashMap,元素作为 key,value 固定为 PRESENT 常量
    • 去重依赖 hashCode() + equals()
    • 插入/删除/查找 平均 O(1),最坏 O(n)(哈希冲突严重时)
    • 无序,迭代顺序不确定
    • 允许一个 null 元素

2. LinkedHashSet

  • 底层数据结构LinkedHashMap<E, Object>
  • 原理
    • 继承 HashSet,内部使用 LinkedHashMap 存储
    • 在 HashMap 基础上维护了一条双向链表记录插入顺序
    • 迭代时按插入顺序返回
    • 性能略低于 HashSet(链表维护开销),但迭代性能更好

3. TreeSet

  • 底层数据结构TreeMap<E, Object>
  • 原理
    • 内部用 TreeMap,元素作为 key
    • 基于红黑树实现,保证元素有序(自然排序或 Comparator)
    • 插入/删除/查找 O(log n)
    • 不允许 null(需要比较)

4. CopyOnWriteArraySet

  • 底层数据结构CopyOnWriteArrayList
  • 原理
    • 内部用 CopyOnWriteArrayList 存储,通过 addIfAbsent() 去重
    • 写操作时复制整个底层数组,读操作无锁
    • 适用于读多写极少的并发场景
    • 迭代时使用快照,不会抛 ConcurrentModificationException

四、Queue / Deque 系列(队列)

1. PriorityQueue

  • 底层数据结构Object[] 数组实现的二叉小顶堆
  • 原理
    • 父节点 i,左子节点 2*i+1,右子节点 2*i+2
    • 插入/删除堆顶 O(log n)
    • 出队总是返回最小元素(自然排序或 Comparator)
    • 不是线程安全
    • 不允许 null

2. ArrayDeque

  • 底层数据结构Object[] 循环数组
  • 原理
    • 通过 headtail 指针实现循环队列
    • 头尾插入/删除均 O(1)(均摊)
    • 扩容时分配新数组(2 倍),重新排列元素
    • 不允许 null(null 作为特殊返回值使用)
    • LinkedList 做栈/队列更高效(数组连续内存,缓存友好)

3. LinkedList(同时实现 Deque)

  • 见上文 List 部分,可作为双向队列使用

4. ConcurrentLinkedQueue

  • 底层数据结构:单向链表 + CAS 无锁
  • 原理
    • 使用 AtomicReference + CAS 操作实现无锁并发
    • tail 节点并非实时更新(惰性更新),减少 CAS 开销
    • 入队:CAS 修改尾节点 next 指针
    • 出队:CAS 修改 head 指针
    • 无界,线程安全,高性能

5. ConcurrentLinkedDeque

  • 底层数据结构:双向链表 + CAS 无锁
  • 原理:与 ConcurrentLinkedQueue 类似,但支持双向操作

6. ArrayBlockingQueue

  • 底层数据结构Object[] 循环数组 + ReentrantLock
  • 原理
    • 有界阻塞队列,创建时必须指定容量
    • 一把 ReentrantLock 控制 puttake,两个 ConditionnotEmpty / notFull)实现阻塞等待
    • 公平/非公平模式可选(公平锁保证 FIFO 顺序)

7. LinkedBlockingQueue

  • 底层数据结构:单向链表 + 两把 ReentrantLock
  • 原理
    • putLock + takeLock 分离,读写可并行
    • 默认容量 Integer.MAX_VALUE(无界风险)
    • notEmpty / notFull 两个 Condition 实现阻塞
    • 吞吐量通常高于 ArrayBlockingQueue

8. PriorityBlockingQueue

  • 底层数据结构Object[] 二叉小顶堆 + ReentrantLock
  • 原理
    • 与 PriorityQueue 相同的堆结构,加上线程安全
    • 无界,自动扩容
    • take() 时队列为空则阻塞等待
    • put() 永不阻塞(无界)

9. SynchronousQueue

  • 底层数据结构:无实际存储(公平模式用链表 TransferQueue,非公平模式用栈 TransferStack)
  • 原理
    • 零容量,每个 put 必须等待一个 take,反之亦然
    • 直接在生产者和消费者之间传递元素
    • 公平模式(FIFO 队列)/ 非公平模式(LIFO 栈)
    • Executors.newCachedThreadPool() 使用此队列

10. DelayQueue

  • 底层数据结构:PriorityQueue + ReentrantLock
  • 原理
    • 元素必须实现 Delayed 接口(getDelay() 返回剩余延迟时间)
    • 内部用 PriorityQueue 按延迟时间排序
    • take() 时如果队首元素未到期则阻塞
    • 适用于定时任务调度、缓存过期等场景

11. LinkedTransferQueue

  • 底层数据结构:单向链表 + CAS
  • 原理
    • 实现 TransferQueue 接口,支持 transfer() 直接传递给消费者
    • 无锁实现,性能优于 LinkedBlockingQueue
    • tryTransfer() 如果有等待的消费者则立即传递,否则返回 false

五、Map 系列(键值对)

1. HashMap

  • 底层数据结构数组 + 链表 + 红黑树(Java 8)
  • 原理
    • 默认初始容量 16,负载因子 0.75,扩容 2 倍
    • 计算 key 的 hash:(h = key.hashCode()) ^ (h >>> 16) 扰动函数减少碰撞
    • 定位桶:index = (n - 1) & hash(等价于取模,要求容量为 2 的幂)
    • 链表长度 >= 8 且数组长度 >= 64 时,链表转红黑树
    • 红黑树节点 <= 6 时,退化回链表
    • 插入/查找/删除 平均 O(1),最坏 O(log n)
    • 允许一个 null key 和多个 null value
    • 非线程安全

2. LinkedHashMap

  • 底层数据结构:HashMap + 双向链表
  • 原理
    • 继承 HashMap,在 Node 基础上增加 before / after 指针
    • 维护一条贯穿所有节点的双向链表
    • 支持插入顺序(默认)或访问顺序accessOrder=true
    • 访问顺序模式下,get() 会将节点移到链表尾部
    • 可重写 removeEldestEntry() 实现 LRU 缓存
    • 迭代顺序 = 链表顺序

3. TreeMap

  • 底层数据结构红黑树
  • 原理
    • key 按自然顺序或 Comparator 排序
    • 红黑树保证平衡,增删查 O(log n)
    • 支持范围查询:subMap()headMap()tailMap()
    • 不允许 null key

4. Hashtable

  • 底层数据结构Entry[] 数组 + 链表
  • 原理
    • 所有方法加 synchronized,线程安全但性能极差
    • 默认容量 11,扩容 2n+1
    • 不允许 null key 和 null value
    • 已被淘汰,使用 ConcurrentHashMap 替代

5. IdentityHashMap

  • 底层数据结构Object[] 数组(key 和 value 交替存储)
  • 原理
    • key 的比较用 ==(引用相等)而非 equals()
    • hash 计算用 System.identityHashCode()
    • 适用于需要区分不同引用相同的对象的场景

6. WeakHashMap

  • 底层数据结构Entry[] 数组 + 链表 + WeakReference
  • 原理
    • key 是 WeakReference,当 key 对象只剩弱引用时,GC 会回收
    • GC 回收 key 后,Entry 会在下次操作时被清除
    • 适用于缓存场景,避免内存泄漏

7. EnumMap

  • 底层数据结构Object[] 数组
  • 原理
    • key 必须是同一枚举类的枚举值
    • 用枚举的 ordinal() 作为数组下标,O(1) 访问
    • 极致性能,内存紧凑
    • 不允许 null key

8. ConcurrentHashMap

  • 底层数据结构数组 + 链表 + 红黑树(Java 8)
  • 原理
    • 取消了 Java 7 的 Segment 分段锁,改用 CAS + synchronized 细粒度锁
    • 锁粒度:锁住链表/红黑树的头节点(桶级别)
    • put() 流程:
      1. 计算 hash 定位桶
      2. 桶为空 → CAS 写入
      3. 桶非空 → synchronized(头节点) 加锁后操作
      4. 链表长度 >= 8 → 转红黑树
    • size() 使用 baseCount + CounterCell[] 分散计数(类似 LongAdder)
    • 不允许 null key 和 null value
    • 线程安全,高并发性能优异

9. ConcurrentSkipListMap

  • 底层数据结构跳表(SkipList)
  • 原理
    • 多层有序链表,底层包含所有节点,上层是下层的"快速通道"
    • 查找从最高层开始,逐层向下,O(log n)
    • 插入时随机决定层数(概率 1/2 升一层)
    • 无锁并发:通过 CAS 操作实现
    • key 有序,支持并发范围查询
    • 适用于需要排序的并发 Map 场景

六、对比速查表

集合 底层结构 有序 线程安全 null 支持 时间复杂度
ArrayList 数组 插入序 允许 get O(1)
LinkedList 双向链表 插入序 允许 头尾 O(1)
HashSet HashMap 无序 允许一个null O(1)
LinkedHashSet LinkedHashMap 插入序 允许一个null O(1)
TreeSet TreeMap 红⿊树 排序序 不允许null O(log n)
PriorityQueue 小顶堆数组 优先级序 不允许null O(log n)
ArrayDeque 循环数组 FIFO/LIFO 不允许null O(1)
HashMap 数组+链表+红黑树 无序 允许一个null key O(1)
LinkedHashMap HashMap+双向链表 插入/访问序 允许一个null key O(1)
TreeMap 红黑树 排序序 不允许null key O(log n)
ConcurrentHashMap 数组+链表+红黑树 无序 不允许null O(1)
ConcurrentSkipListMap 跳表 排序序 不允许null O(log n)
ArrayBlockingQueue 循环数组+锁 FIFO 不允许null O(1)
LinkedBlockingQueue 链表+锁 FIFO 不允许null O(1)
SynchronousQueue 无存储 直传 不允许null -

七、选型建议

需要随机访问? → ArrayList
频繁头插/头删? → ArrayDeque / LinkedList
需要去重? → HashSet(无序)/ LinkedHashSet(有序)/ TreeSet(排序)
需要排序Map? → TreeMap / ConcurrentSkipListMap
需要LRU缓存? → LinkedHashMap (accessOrder=true)
需要并发? → ConcurrentHashMap / ConcurrentSkipListMap
需要阻塞队列? → ArrayBlockingQueue(有界) / LinkedBlockingQueue / SynchronousQueue
需要延迟队列? → DelayQueue
枚举做key? → EnumMap(性能最优)
posted @ 2026-05-12 16:56  webzd  阅读(18)  评论(0)    收藏  举报