CopyOnWriteArrayList

解决脏读问题;牺牲写的效率,提高读的效率

CopyOnWriteArrayList是一种读写分离的思想体现的ArrayList;

它将读写的操作对象分离开来;

写的过程中,通过复制出一片新的内存,在新的内存中执行完成写操作,再赋值回去,完成写操作;

在写的过程中,可以进行并发的读,因为操作的并不是同一片内存;

这样就避免了java.util.ConcurrentModificationException并发修改异常了;

下面一步步来看一下源码,怎么实现的?

只分析了部分常用的API的源码:读取get和写入add

构造器

直接看源码,不是很复杂;

public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable { final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array; //数据都会存储在这个array中
// 提供set,get方法
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}
// ①无参构造器
public CopyOnWriteArrayList() {
setArray(new Object[0]); // 初始化一个长度0的array
}
// ②将一个Collection转化为CopyOnWriteArrayList
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
// 此Collection就是CopyOnWriteArrayList,直接赋值
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
// 其余都转化为Object数组赋值
elements = c.toArray();
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(elements);
}
// ③直接传入一个泛型数组
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

add

添加方法,此类的重点方法:即:写操作的实现;

CopyOnWrite容器,即写时复制的容器;

添加元素的时候,并不直接添加,而是先将array复制一份给 Object[ ] newElements,且newElements长度加1,表示要添加一个元素;

添加的操作,都是针对newElements进行的,不对原array进行操作;

这样就将,写操作的内存,与读操作的内存分离开来,写的过程不会影响并发读取;

源码:

// 添加方法
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
newElements[len] = e;// 添加元素
setArray(newElements);// 将添加完成的newElements赋值给原array
return true;
} finally {
lock.unlock();
}
}
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}

get

读取操作,没有做任何的同步措施;

array并不会发生修改,只会在写操作后,直接替换,不存在数据安全问题;

public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}
final Object[] getArray() {
return array;
}

最新文章

  1. Client Window坐标 RECT相关函数
  2. UIkit框架之uiUIapplication
  3. Masonry控制台打印约束冲突问题解决
  4. 10个出色的NoSQL数据库
  5. 【ufldl tutorial】Softmax Regression
  6. [转] Web前端优化之 Javascript篇
  7. POJ 3525 Most Distant Point from the Sea
  8. MyISAM 存储引擎
  9. linq之延迟加载和即时加载+标准查询运算符
  10. 利用JavaScript实现动态显示表格且对应改变按键的value值
  11. java8新特性学习笔记链接
  12. c函数指针
  13. python 单例模式总结
  14. Unity中调用DLL库
  15. BigDecimal的一些用法
  16. Python实例属性限制(__slots__)
  17. Javascript中变量函数申明优先级
  18. 论文笔记——ThiNet: A Filter Level Pruning Method for Deep Neural Network Compreesion
  19. MQ之如何做到消息幂等 (转 优秀)
  20. destoon的如何显示tag生成的sql语句

热门文章

  1. firewall防火墙常用操作
  2. 某表中字段值存在多个Gid逗号分开 取值拆分每个gid SQL多个逗号隔开的取值
  3. Microsoft OLE DB Provider for Oracle 在哪个安装包中
  4. LeetCode:四数之和【18】
  5. java打包小记
  6. (CSDN迁移) Java路径获取
  7. 第07组 Beta冲刺(3/4)
  8. jquery向上滚动页面的写法
  9. Kafka性能调优 - Kafka优化的方法
  10. sql查询出现1055 this is incompatible with sql_mode=only_full_group_by