多线程开发中List的使用

由于ArrayList在多线程高并发情况下是不安全的,因此要慎用,那么此时如果涉及到集合操作,应该怎么选:

方案一:Vector:

特点:通过给所有方法都用 synchronized 修饰从而保证线程安全,

缺点:CopyOnWriteArrayList

  • 高并发场景下性能较差(锁竞争严重)。

  • 即使单线程环境也会因同步开销影响性能。

总结:不建议使用。

方案二:Collections.synchronizedList

特点:低并发读写,简单封装 ArrayList,所有方法加锁。

缺点:高并必情况下性能不如CopyOnWriteArrayList

使用示例:

java 复制代码
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// 复合操作仍需外部同步
synchronized (syncList) {
    if (!syncList.contains("value")) {
        syncList.add("value");
    }
}

方案三:CopyOnWriteArrayList

特点:

1.读操作:无锁,直接访问底层数组;

2.写操作 :复制新数组,修改后替换旧数组(适合 读多写极少 的场景)。

缺点:

1.写操作开销大(需复制数组)。

2.数据一致性弱:读取的是某一时刻的快照,可能读到旧数据。

使用示例:

java 复制代码
// 示例:事件监听器列表
private final List<Listener> listeners = new CopyOnWriteArrayList<>();

拓展:

CopyOnwriteArrayList通过JUC包下的lock来实现线程间的同步的, 可实现了读读操作和读写操作不互斥。

它是怎么实现读写不互斥的呢?

在面临写操作的时候,CopyOnwriteArrayList会先复制原来的数组并且在新数组上进行修改,最后再将原数组覆盖。如果写操作过程中发生了线程切换。并且切换到读线程,因为此时数组并未发生覆盖,读操作读取的还是原数组。另外,数组定义private transient volatile Object\[\] array,其中采用volatile修饰,保证内存可见性,读取线程可以马上知道这个修改。也就是说当读写并发时读操作是在旧数组中读到的旧值(一致性弱)。

方案四:ConcurrentLinkedQueue

特点:

1.高并发队列操作(如任务分发),基于 CAS 无锁实现。

2.线程安全:多线程并发添加无需额外同步。

  1. 无阻塞:操作立即返回,不会因锁竞争导致线程挂起。

  2. 无容量限制:队列会动态扩展。

缺点

1.不支持随机访问(非 List 接口实现)。

2.弱一致性:迭代器创建后,其他线程的修改可能不会立即反映到遍历中。

3**.** 不支持 remove() 操作:尝试通过迭代器删除元素会抛出 UnsupportedOperationException

使用示例:

java 复制代码
public class Main {
    public static void main(String[] args) {
        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
        
        // 添加元素(推荐使用 offer)
        queue.offer("A"); // 返回 true 表示成功
        queue.add("B");   // 与 offer 等效
       

        // 读取并移除头部元素
        String head1 = queue.poll(); // 返回 "A",队列变为 [B]
        System.out.println("Polled: " + head1);

        // 仅读取头部元素(不移除)
        String head2 = queue.peek(); // 返回 "B",队列仍为 [B]
        System.out.println("Peeked: " + head2);

        // 队列为空时
        queue.poll();               // 移除 "B",队列为空 []
        String head3 = queue.poll(); // 返回 null
        System.out.println("Polled empty: " + head3);
    }
}

方案五:ConcurrentHashMap

特点:可实现高性能随机访问,需要设置KEY.

方案对比:

开发推荐

现代开发中更推荐 CopyOnWriteArrayList

  • 无锁读取:适合多核 CPU 环境,避免线程阻塞。

  • 代码简洁:无需手动同步,减少错误。

  • 安全迭代 :迭代器不会抛出 ConcurrentModificationException

但需注意其 内存占用(写时复制会占用双倍空间)。

相关推荐
Lhappy嘻嘻27 分钟前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
伊玛目的门徒1 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
懒鸟一枚4 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
我命由我123455 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑5 小时前
Sentinel安装
java·后端·微服务
凤凰院凶涛QAQ7 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案8 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
猿与禅8 小时前
CosId 分布式 ID 生成器完全教程:从架构原理到生产落地
java·shardingsphere·雪花算法·分布式id·高性能·cosid·号段模式
MindUp8 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG4778 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程