文章目录
前言
CopyOnWrite是一种读写分离的思路,写入的时候会对原数组copy一份出来然后再做修改,适用于读多写少的场景,可以最大程度提升读效率。
1、源码解析
1.1、读写分离图示
1.2、重要属性
lock
:用于实现写写互斥的,保证同一时刻只有一个线程在进行修改array
:存储元素的容器,这里使用volatile
标注,是为了防止写线程和读线程没有运行在同一个核心上,产生数据变更后不可见的问题。
1.3、构造函数
- 无参构造函数:这里会创建一个空数组
- 带参构造函数:如果参数是
cow
类型的,那么直接赋值,如果不是,那么转成数组然后再对元素进行copy
1.4、常用方法解析
1.4.1、add(E e)
方法解析
- 首先进行加锁,避免写写冲突
- 对旧数组进行
copy
,然后再copy
出来的数组上插入新元素- 将
copy
数组赋值给数组引用,覆盖原数组
1.4.2、add(int index, E element)
方法解析
- 首先加锁,避免写写冲突
- 获取旧数组,然后对下标做下越界判断。
- 对插入的下标位置做判断,如果是最后一个位置那么直接拷贝一个
n+1
的数组,然后把元素添加到最后,如果是在中间,那么就会分两次进行拷贝,把idx
的位置空出来用以插入元素。- 把引用指向新数组,覆盖原有数组
- 释放锁
1.4.3、get(int index)
方法解析
- 这里读取是无锁的,直接根据读取数组对应下标的元素
1.4.4、remove(int index)
方法解析
- 加锁,避免冲突
- 根据下标判断删除的是不是最后一个元素,如果是最后一个则直接创建一个
n-1
的新数组,copy
就行了,如果是中间位置,则会进行两次拷贝,第二次拷贝会往前挪动一个位置,这样就把原有idx
的位置元素覆盖掉了。
总结
从上面方法的源码流程可以看出cow
也是存在很多的弊端的,因为读写分离,其实我们读取的数据可能不是最新的一份数组,所以不保证实时一致性,只保证最终一致性,而且如果是读写均匀或者写多读少的情况下,那么就会造成存在多份副本数据,这个时候就会造成jvm
频繁的GC
。