Skip to content

JUC 集合选择

Java 并发包里集合那么多,什么时候用哪个?

选对了,性能飞起;选错了,可能比普通集合还慢。本文帮你做出正确的选择。

快速决策表

需要线程安全的集合?

  ├── Map
  │     ├── 高并发,需要排序        → ConcurrentSkipListMap
  │     ├── 高并发,通用场景         → ConcurrentHashMap ✅
  │     └── 读多写少                → ConcurrentHashMap + LongAdder

  ├── List
  │     ├── 读多写少                → CopyOnWriteArrayList ✅
  │     └── 写多读少                → Collections.synchronizedList

  ├── Set
  │     ├── 高并发                  → ConcurrentHashMap.newKeySet()
  │     └── 读多写少                → CopyOnWriteArraySet

  └── Queue
        ├── 需要阻塞(生产者-消费者) → BlockingQueue
        │     ├── 固定大小限流         → ArrayBlockingQueue
        │     ├── 高性能无界          → LinkedBlockingQueue
        │     └── 优先级              → PriorityBlockingQueue

        ├── 延迟执行                → DelayQueue

        └── 非阻塞                  → ConcurrentLinkedQueue ✅
              └── 需要双端操作        → ConcurrentLinkedDeque

Map 选择

对比表

Map并发度特性适用场景
ConcurrentHashMap桶级锁通用场景
ConcurrentSkipListMap有序,无锁需要排序的场景
Hashtable全局锁不推荐
synchronizedMap全局锁不推荐

选择指南

java
// 高并发通用场景
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();

// 需要排序的高并发场景
ConcurrentSkipListMap<String, Integer> cslm =
    new ConcurrentSkipListMap<>();

// 高并发 Set(基于 ConcurrentHashMap)
Set<String> concurrentSet = chm.newKeySet();

// 高性能计数
ConcurrentHashMap<String, LongAdder> counter = new ConcurrentHashMap<>();
counter.computeIfAbsent("key", k -> new LongAdder()).increment();

List 选择

对比表

List读性能写性能迭代器适用场景
CopyOnWriteArrayList极高(无锁)低(复制)弱一致读多写少
synchronizedList低(有锁)低(有锁)快速失败写多读少
Vector低(有锁)低(有锁)快速失败不推荐

选择指南

java
// 读多写少(配置、黑名单)
CopyOnWriteArrayList<String> config = new CopyOnWriteArrayList<>();

// 写多读少
List<String> syncList = Collections.synchronizedList(new ArrayList<>());

选择原则:写入频率 > 读频率的 1% 时,不考虑 CopyOnWriteArrayList。

Set 选择

对比表

Set实现特性适用场景
ConcurrentHashMap.newKeySet()CHM高并发,无序高并发
CopyOnWriteArraySetCOWList读多写少读多写少
Collections.synchronizedSetsynchronized全局锁不推荐

选择指南

java
// 高并发 Set
Set<String> concurrentSet = new ConcurrentHashMap<String, Boolean>().newKeySet();

// 读多写少的 Set
CopyOnWriteArraySet<String> cowSet = new CopyOnWriteArraySet<>();

Queue 选择

阻塞队列

队列特性适用场景
ArrayBlockingQueue有界 FIFO,固定大小限流
LinkedBlockingQueue可选有界,性能高生产者-消费者
PriorityBlockingQueue优先级,无界任务调度
DelayQueue延迟元素定时任务、缓存
SynchronousQueue不存储元素线程同步
java
// 限流:有界队列
BlockingQueue<Task> limiter = new ArrayBlockingQueue<>(100);

// 生产者-消费者
BlockingQueue<Task> queue = new LinkedBlockingQueue<>(1000);

// 优先级调度
PriorityBlockingQueue<Task> priorityQueue = new PriorityBlockingQueue<>();

// 定时任务
DelayQueue<DelayedTask> delayQueue = new DelayQueue<>();

// 线程同步(不存储)
SynchronousQueue<Task> syncQueue = new SynchronousQueue<>();

非阻塞队列

队列特性适用场景
ConcurrentLinkedQueue无界 FIFO,无锁高性能非阻塞
ConcurrentLinkedDeque无界双端,无锁工作窃取
java
// 高性能非阻塞
ConcurrentLinkedQueue<Task> queue = new ConcurrentLinkedQueue<>();

// 双端队列
ConcurrentLinkedDeque<Task> deque = new ConcurrentLinkedDeque<>();

选择口诀

Map → ConcurrentHashMap(默认)
      需要排序 → ConcurrentSkipListMap

List → 读多写少 → CopyOnWriteArrayList
      否则 → Collections.synchronizedList

Set → 高并发 → ConcurrentHashMap.newKeySet()
      读多写少 → CopyOnWriteArraySet

Queue → 需要阻塞 → BlockingQueue
        ├─ 限流 → ArrayBlockingQueue
        ├─ 生产者-消费者 → LinkedBlockingQueue
        └─ 优先级 → PriorityBlockingQueue
        不需要阻塞 → ConcurrentLinkedQueue

性能对比

场景推荐选择说明
高并发读 MapConcurrentHashMapget() 无锁
高并发写 MapConcurrentHashMap桶级锁
高并发计数ConcurrentHashMap + LongAdder分段累加
读多写少 ListCopyOnWriteArrayList读无锁
生产者-消费者LinkedBlockingQueue阻塞语义
非阻塞高性能ConcurrentLinkedQueue无锁
定时任务DelayQueue延迟获取

注意事项

  1. 不要用 Hashtable / Vector:性能差,API 旧
  2. 不要用 Collections.synchronizedMap/List:全局锁,并发度低
  3. ConcurrentHashMap 的 key/value 不能为 null:与其他 Map 不同
  4. CopyOnWriteArrayList 写操作要谨慎:每次复制整个数组
  5. size() 可能不精确:Concurrent 系列通常如此

要点回顾

  • Map:ConcurrentHashMap 是默认选择,需要排序用 ConcurrentSkipListMap
  • List:读多写少用 CopyOnWriteArrayList
  • Set:高并发用 ConcurrentHashMap.newKeySet(),读多写少用 CopyOnWriteArraySet
  • Queue:需要阻塞用 BlockingQueue,不需要阻塞用 ConcurrentLinkedQueue

相关链接

基于 VitePress 构建