CopyOnWriteArrayList
线程安全版本ArrayList
-
新增元素
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock();//进行加锁 try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1);//元素组进行拷贝 newElements[len] = e;//将新元素加入到新数组中 setArray(newElements);//新数组重新赋值予原数组 return true; } finally { lock.unlock();//释放锁 } }
- 每新加一个元素都会发生一次全数组拷贝
- 通过add(index,element)增加元素类似
- 类似于ArrayList通过addAll进行批量的增加效率要高于单个加入
-
元素的删除
public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock();//加锁 try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; if (numMoved == 0)//当移除最后一个元素时 setArray(Arrays.copyOf(elements, len - 1)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index);//分段拷贝 System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements);//元数据覆盖 } return oldValue; } finally { lock.unlock(); } }
- 发生一次数组对象拷贝
- 直接移除元素时,先找到其索引,然后通过以上方法进行移除
- 同样批量删除的效率高于单个删除
-
内部类
- COWIterator
- next 向后访问
- previous 向前访问
- nextIndex 查看下一个索引值
- previousIndex 前一个索引值
- 不支持操作:remove,set,add
- 取值过程不进行mod的检查
- Spliterators.spliterator
- COWSubList
- COWIterator
-
特点
- 变更操作基本是先拷贝出一个副本,操作副本完成后,用副本更新原数据
SynchronizedList
线程安全List
-
在get/set/add/remove/indexOf/sort 内部对象进行加锁处理
public E get(int index) { synchronized (mutex) {return list.get(index);} }
加锁粒度比较大
两者对比
- CopyOnWriteArrayList在数据读上占据优势
- CopyOnWriteArrayList需要更大的内存空间
- SynchronizedList使用迭代器需要自己进行线程的同步