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