CopyOnWriteArrayList
ArrayList在单线程下是高效的,但是在多线程下是线程不安全的
ArrayList在多线程的线程不安全的几种体现
- 删除元素时。a和b同时删除索引为4个数据。这个时候a线程先执行 将4后面的元素往前移动一位。size-- 这个时候b线程也删除 就删除到别的元素。如果是删除第一个元素。a线程size--后。a再功能size去获取 就会报索引越界
- 添加元素时 a b线程同时add a 判断这时往下标为0的位置加元素 size还没++ 这个时候b也执行add方法也是判断往下标为0的地方添加元素 a往下标为0的位置填入数据 size++ b也往0的位置添加元素 覆盖了a的值 size++ 这个时候遍历会出现索引溢出
- 同时读和删的时候同理。for i++ 这个时候元素已经删除了。。或者移动了 导致数据错乱(因为list本质是数组 删除元素 只将后面元素往前移)
- 迭代器如何解决又在读又在写的问题 可以参考https://www.cnblogs.com/LQBlog/p/12713238.html#autoid-6-2-0
public static void main(String[] args) throws InterruptedException { // CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>(); // Vector<String> list=new Vector<String>(); List<String> list = new ArrayList<String>(); new Thread(new Runnable() { @Override public void run() { while (true) { for (int i = 0; i < list.size(); i++) { list.get(i); } } } }).start(); for (int i = 0; i < 2; i++) { new Thread(new Runnable() { int j = 0; @Override public void run() { while (j < 1000) { j++; list.add("test"); } } }).start(); } Thread.sleep(5000); System.out.println(list.size()); }
执行这段代码会报索引溢出。。使用注释的代码便不会。Vector 跟hashTable一样 在所有方法都加了sychronized关键字。性能很低
CopyOnWriteArrayList 只是在add的时候加了锁 读的时候没加锁。 在写的时候将原来数组copy一份。然后加入新的值 再将新的数组引用替换旧的数组引用达到了读写分离。
CopyOnWriteArrayList 使用需要注意的几个点
在读多写少的时候使用
因为CopyOnWriteArrayList为了保证添加的时候副本只有一个 在add方法是加了锁的
在不要求数据实时性的时候使用
CopyOnWriterArrayList为了提高多线程访问的效率。在读时没有加锁。但是在写的时候操作的是副本 读的时候操作的是原来的容器
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!