网站添加flash,重庆建一个网站,html5网站推广,阿里云wordpress搭建网站一、CopyOnWriteArrayList 源码解读
在 JUC 中#xff0c;对于 ArrayList 的线程安全用法#xff0c;比较推崇于使用 CopyOnWriteArrayList #xff0c;那 CopyOnWriteArrayList是怎么解决线程安全问题的呢#xff0c;本文带领大家一起解读下 CopyOnWriteArrayList 的源码…一、CopyOnWriteArrayList 源码解读
在 JUC 中对于 ArrayList 的线程安全用法比较推崇于使用 CopyOnWriteArrayList 那 CopyOnWriteArrayList是怎么解决线程安全问题的呢本文带领大家一起解读下 CopyOnWriteArrayList 的源码主要对几个常用的函数进行讲解。
在进行 CopyOnWriteArrayList 的源码讲解之前先看下同样实现了线程安全的 Vector 很多文章都说不推荐使用 Vector 其主要原因是性能太差了那性能为什么这么差呢可以看下 Vector add 和 get 的源码 Vector 的添加和读取操作都被加上了 synchronized 锁当并发情况下因为锁的存在相当于变成了单线程的操作所以效率肯定低同样这样的优点就是保证了数据的唯一性不会读取到脏数据。
下面再看下 CopyOnWriteArrayList 是如何解决并发问题的呢。
首先看下 CopyOnWriteArrayList 的全局变量有哪些 其中 lock 锁就是每次在做写操作时锁的句柄array 就是具体存储数据的数组注意这里的 array 被 volatile 所修饰因此可以在并发情况下实现数据的可见性。
当 new 创建了一个 CopyOnWriteArrayList 时如果是使用无参的构造函数则将 array 的长度默认成 0 创建了一个空的数组。 在使用 add 添加数据时先使用 lock 上锁并获取到当前的 array 数组然后对 array 进行 copyOf新的数组的长度是之前的长度 1 这样才能存放当前新的值将新值填充后再替换掉旧的 array 数组后释放当前锁。 在使用 get 获取指定下边数据时直接对当前的 array 进行操作 在进行 remove 删除时先使用 lock 上锁然后再获取当前的 array 数组如果传入的 index 正好是最后一个那么 numMoved 计算出来就是 0 则使用 copyOf 长度进行 -1 去除最后一个数据。否则传入的不是最后一个先声明一个新的 array 数组数组的长度就是旧的 array 的 len - 1再将 0 到 index 的数据 arraycopy 至新的 array 数组然后再将 index 1 后的再 arraycopy 至新的 array 数组最后将新的 array 数组替换旧的然后释放锁。 二、总结
当 new 新建一个 CopyOnWriteArrayList 后会生成一个数组 array 来存放添加的内容如果是无参的构造函数则 array 的长度为 0 添加数据时再进行扩容。同时会声明一个 ReentrantLock 锁。当进行 add 操作时先进行上锁然后对当前的 array 进行 copyOf并且新的长度是之前的长度 1 这样才能存放当前新的值将新值填充后再替换掉旧的 array 数组后释放当前锁。当使用 get 获取数据时无需上锁直接读取当前 array 数组的指定位置。当使用 remove 时同样先进行上锁然后再获取当前的 array 数组如果传入的 index 正好是最后一个则使用 copyOf 长度进行 -1 否则的话先声明一个新的 array 数组现将0 到 index 的数据 arraycopy 至新的 array 数组然后再将 index 1 后的再 arraycopy 至新的 array 数组最后将新的 array 数组替换旧的然后释放锁。
读下来之后可以感觉出来 CopyOnWriteArrayList 的源码非常容易理解和阅读同时我们也可以看出一些问题CopyOnWriteArrayList 实现了写写隔离但读读是可以共享的这就有可能出现当某个数据再修改时读进行了操作导致读取到的还是旧的数据。还有就是每次写操作都对数组进行 Copy 假如数据量非常大的情况下进行 Copy 消耗的资源则会进行 x 2 因此使用 CopyOnWriteArrayList 时需要考虑下自己的数据量以及读写的频次。