资讯动态

《CopyOnWriteArrayList 源码阅读》

发布时间:2026/10/18 14:08:59 来源:尧图企业网站定制
简介CopyOnWriteArrayList 是线程安全的 List。读写分离思想读操作无锁写操作add/set/remove加独占锁复制一份新数组修改新数组最后将引用指向新数组。旧数组不会被修改所有读线程继续访问旧数组不会阻塞读。适合读多写少场景缓存、事件监听写操作会复制数组大数据量写开销大。一、锁与底层数组定义// 独占锁所有修改操作共用这一把锁finaltransientReentrantLocklocknewReentrantLock();// 底层存储数组volatile修饰保证引用可见性privatetransientvolatileObject[]array;// 获取数组finalObject[]getArray(){returnarray;}// 设置数组引用finalvoidsetArray(Object[]a){arraya;}lockReentrantLock 可重入独占锁写操作必须获取锁防止多个写线程并发复制多个数组volatile Object[] arrayvolatile 保证数组引用修改对其他线程立即可见数组内部元素不具备 volatile 可见性。二、add () 方法源码publicbooleanadd(Ee){finalReentrantLocklockthis.lock;lock.lock();// 加锁try{Object[]elementsgetArray();intlenelements.length;// 复制原数组到新数组长度1Object[]newElementsArrays.copyOf(elements,len1);newElements[len]e;// 新元素放入末尾setArray(newElements);// 将array引用指向新数组returntrue;}finally{lock.unlock();// 释放锁finally保证锁一定释放}}add () 作用1.获取独占锁阻止其他写线程并发修改2.获取当前底层数组复制生成长度 1的全新数组3.在新数组尾部添加元素4.将成员变量 array 引用指向新数组5.finally 释放锁。关键点全程不修改原数组原数组保持不变读线程仍然读取旧数组。三、remove (int index) 方法源码publicEremove(intindex){finalReentrantLocklockthis.lock;lock.lock();try{Object[]elementsgetArray();intlenelements.length;EoldValueget(elements,index);// 获取待删除旧值intnumMovedlen-index-1;Object[]newElements;if(numMoved0)// 删除最后一个元素复制长度len-1newElementsArrays.copyOf(elements,len-1);else{newElementsnewObject[len-1];// 分段拷贝index前复制index之后向前移动一位System.arraycopy(elements,0,newElements,0,index);System.arraycopy(elements,index1,newElements,index,numMoved);}setArray(newElements);returnoldValue;}finally{lock.unlock();}}remove () 作用1.加锁2.获取原数组取出待删除位置元素3.创建长度len-1新数组4.通过System.arraycopy把原数组除 index 位置以外的数据拷贝到新数组5.array 引用切换到新数组返回被删除元素释放锁。四、set (int index, E element) 方法源码publicEset(intindex,Eelement){finalReentrantLocklockthis.lock;lock.lock();try{Object[]elementsgetArray();EoldValueget(elements,index);if(oldValueelement){// 新旧值相等不需要复制数组直接返回旧值returnoldValue;}Object[]newElementsArrays.copyOf(elements,elements.length);newElements[index]element;setArray(newElements);returnoldValue;}finally{lock.unlock();}}set () 作用1.加锁2.获取原数组取出 index 位置旧值3.如果新旧对象完全相同无需复制数组直接返回4.复制完整新数组修改新数组指定下标5.替换 array 引用返回旧值释放锁。五、get (int index) 方法源码publicEget(intindex){returnget(getArray(),index);}privateEget(Object[]a,intindex){return(E)a[index];}get () 作用读操作不加锁直接获取当前volatile array引用通过下标取值。弱一致性读取的是数组快照。线程读取期间其他线程执行 add/remove/set会生成新数组但当前读线程仍然访问旧数组无法实时感知最新写入的数据。小结1.写操作add/set/remove加ReentrantLock拷贝新数组修改新数组切换引用2.读操作 get无锁读取数组快照读写互不阻塞3.优点读性能高缺点写拷贝开销大、占用额外内存只能保证弱一致性4.使用场景读多写少如本地配置缓存、事件订阅列表。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑