Java中各种线程安全的 List的使用场景和区别

Java 并发编程中,提供了多种 线程安全的 List,每种适用于不同的场景。以下是常见的 并发 List 类及其特点:


1. CopyOnWriteArrayList

  • 适用场景读多写少(如缓存、配置更新等)
  • 底层原理:写操作时 复制整个数组,然后替换旧数组,保证读写不会冲突。
  • 优点
    • 读操作 无锁,性能高。
    • 迭代器 不会抛出 ConcurrentModificationException,即 弱一致性
  • 缺点
    • 写操作昂贵(每次写都会复制整个数组)。
    • 适用于 小数据量,否则会影响性能。

示例:

List list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
System.out.println(list);

2. Collections.synchronizedList(new ArrayList<>())

  • 适用场景:适合 并发场景但写入量不高
  • 底层原理:对 所有方法 都加了 synchronized,保证线程安全。
  • 优点
    • 兼容 传统 ArrayList 的使用方式。
    • 适用于 写入较少的场景
  • 缺点
    • 锁粒度大,写入竞争激烈时会影响性能。
    • 迭代时需要手动加锁,避免 ConcurrentModificationException

示例:

List list = Collections.synchronizedList(new ArrayList<>());
synchronized (list) {  // 迭代时手动加锁
    for (String s : list) {
        System.out.println(s);
    }
}

3. ConcurrentLinkedQueue(推荐写多场景)

  • 适用场景写多读少(高并发队列、日志收集等)。
  • 底层原理无锁CAS(Compare-And-Swap) 方式操作链表节点。
  • 优点
    • 高并发写入性能好,不需要全局锁。
    • 无锁队列,性能比 synchronizedList 好。
  • 缺点
    • 不是严格的 List,而是 Queue,不能随机访问(只能按顺序遍历)。

示例:

Queue queue = new ConcurrentLinkedQueue<>();
queue.add("A");
queue.add("B");
System.out.println(queue.poll());  // A

4. BlockingQueue(阻塞队列,适用于生产者-消费者模式)

  • 适用场景:需要限流 或者 生产者-消费者 场景,如消息队列。
  • 实现类
    • LinkedBlockingQueue基于链表,容量可选)
    • ArrayBlockingQueue基于数组,固定大小)
    • PriorityBlockingQueue支持优先级排序
    • DelayQueue支持延迟消费
  • 优点
    • 支持容量限制,可以用 take() 阻塞线程,避免过载。
    • 适用于 线程池任务队列、消息队列等 场景。
  • 缺点
    • 需要 poll()take() 取数据,不能像 List 那样随机访问。

示例:

BlockingQueue queue = new LinkedBlockingQueue<>();
queue.put("A");  // 生产者
String item = queue.take();  // 消费者,若队列为空则阻塞

5. ConcurrentSkipListMap(支持排序,适合有序并发集合)

  • 适用场景:需要排序或者按 key 查询的并发场景。
  • 底层原理:跳表(Skip List),比 TreeMap 适用于高并发。
  • 优点
    • 读写性能比 TreeMap 更适合高并发。
    • 有序存储,可以用 firstKey()lastKey() 获取最小/最大值。
  • 缺点
    • 写入比 ConcurrentHashMap,适合需要排序的场景。

示例:

ConcurrentSkipListMap map = new ConcurrentSkipListMap<>();
map.put(3, "C");
map.put(1, "A");
map.put(2, "B");
System.out.println(map.firstKey());  // 1

6. ConcurrentHashMap + List(适合大数据量、分类存储)

  • 适用场景:当数据量大,且需要按分类存储时。
  • 实现方式ConcurrentHashMap>,保证不同 key 并发访问时不会影响彼此。
  • 优点
    • 并发性能比 CopyOnWriteArrayList 好,且避免了 synchronizedList 的锁竞争。
    • 适用于大数据量存储,如按 key 进行分区。
  • 缺点
    • 需要手动管理 List 的同步。

示例:

ConcurrentHashMap> map = new ConcurrentHashMap<>();
map.putIfAbsent("A", Collections.synchronizedList(new ArrayList<>()));
map.get("A").add("Hello");
System.out.println(map.get("A"));

区别

类型 适用场景 读写性能 备注
CopyOnWriteArrayList 读多写少 读快,写慢 适用于缓存、黑名单、白名单
Collections.synchronizedList 低并发写入 加锁读写 兼容 ArrayList
ConcurrentLinkedQueue 写多读少 无锁写,高性能 适用于日志收集、队列
BlockingQueue 生产者-消费者 支持限流 适用于任务队列
ConcurrentSkipListMap 有序存储 TreeMap 并发性能好 适用于排行榜有序存储
ConcurrentHashMap + List 大数据量,分类存储 读写快,按 key 并发 适用于按 key 组织数据

使用场景

  • 如果数据量大,且写入频繁ConcurrentLinkedQueue
  • 如果是缓存数据,读多写少CopyOnWriteArrayList
  • 如果需要生产者-消费者模式BlockingQueue
  • 如果需要存储有序数据ConcurrentSkipListMap
  • 如果数据分类存储ConcurrentHashMap>

如果你的场景 写多、并发量大,推荐 ConcurrentLinkedQueueConcurrentHashMap 结合 List 的方式

你可能感兴趣的:(java)