快速学习Java中的CopyOnWrite集合

CopyOnWrite集合还是比较简单的 , 这里做一个简单的介绍 。
基础概念CopyOnWrite翻译过来就是在写的时候才复制 , 写入时复制是计算机程序设计领域中的一种优化策略 。 主要思路是如果有多个调用者同时要求相同的资源 , 他们会共同获取相同的指针指向相同的资源 , 直到某个调用者视图修改资源内容时 , 系统才会真正复制一份专用副本给该调用者 , 而其他调用者所见到的最初的资源仍然保持不变 。 这过程对其他的调用者都是透明的 。 此做法主要的优点是如果调用者没有修改资源 , 就不会有副本被创建 , 因此多个调用者只是读取操作时可以共享同一份资源 。
在Java中CopyOnWrite集合只有两个类CopyOnWriteArrayList、CopyOnWriteArraySet , 而CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的 , 所以我们只用看看CopyOnWriteArrayList的实现就能清楚CopyOnWrite的实现了 。
CopyOnWriteArrayList基础结构首先是基础属性 , 直接看源码 , 如下图:
快速学习Java中的CopyOnWrite集合文章插图
可以看到结构还是比较简单的 , 一个ReentrantLock的锁lock和一个transient与volatile修饰的Object数组array 。 lock保证线程安全介绍后面的方法会用到 , array用来保存数据 。
添加方法添加数据的方法有两类分别为set和add方法 , 源码如下图:
快速学习Java中的CopyOnWrite集合文章插图
两个方法流程比较相似 , 都是先获取到锁 , 然后复制出一个数组新的数组 , set方法的新数组长度不变 , add方法新数组长度加1, , set方法是更新新数组的指定位置元素 , add方法是把数据添加到新数组的最后 , 在最后在把新数组设置给array属性 。
移除方法移除方法也分两个 , 一个是移除指定索引处的元素 , 一个是移除指定对象的元素 , 首先是指定索引的方法 , 源码如下图:
快速学习Java中的CopyOnWrite集合文章插图
移除指定索引方法还是比较简单的 , 仍然是先获取到锁 , 然后判断索引位置 , 如果是最后一个元素 , 则只用把旧数组中从0到倒数第二个的元素复制到新的数组中就行了 。 如果不是最后一个旧数组按索引位置分段复制到新数组就行 。
移除指定对象的方法稍微复杂一点 , 源码如下图:
快速学习Java中的CopyOnWrite集合文章插图
【快速学习Java中的CopyOnWrite集合】首先获取到array的快照 , 再找到对象在数组中的位置 , 最后才加锁找到对象在最新的array中的位置 , 根据位置分段进行复制 。
总结这里只分析了更新数据的主要方法 , 因为查询方法不涉及到加锁和数组的变化整体都比较简单 , 所以就不去介绍了 。
主要是通过分析这几个方法来深入理解CopyOnWrite的思想 , 通过源码分析发现查询方法都没有加锁 , 更新方法都加了锁 , 并且每次更新都是先复制一份 , 然后在准备好后再更新array , 所以新增进去的数据可能不会及时的读到 。
所以CopyOnWrite容器只能保证数据的最终一致性 , 但是不能保证数据的实时一致性 。 不过CopyOnWrite容器比较适用于那些读多写少的场景 。
Java程序员日常学习笔记 , 如理解有误欢迎各位交流讨论!
快速学习Java中的CopyOnWrite集合文章插图


    推荐阅读