(一)、不安全的案例(待补充):
(二)解决方案一:使用CopyOnWriteArrayList代替ArrayList
(1)如下面三张图ArrayList底层其实是一个数组
(2)CopyOnWriteArrayList底层数组是用volatile 和 transient修饰的。
private transient volatile Object[] array;
volatile 其中一个作用就是线程的可见性,当一个线程修改一个共享变量时,另外一个线程能立即读到这个修改的值。
(3)分析CopyOnWriteArrayList的add方法源码
①本质还是用到了锁。
②Object[] elements = getArray();就是获取到底层的数组
点进去看getArray()
③int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
创建一个新的数组,元素为老数组,长度为老数组+1
关于Arrays的copyOfcopyOf(T[] original, int newLength)
Arrays的copyOf()方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。
copyOf()的第一个参数是旧的数组,第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值
④newElements[len] = e;
将add方法的参数放倒数组最后一位(本来新数组也就比旧数组长一位)
⑤setArray(newElements); 将新数组赋值给底层数组
(4)分析CopyOnWriteArrayList的get方法源码
可以看到没有锁的存在。
(5)add 方法执行到setArray(newElements)一个注意点(一个介绍视频中说的)
由于数组是volatile,所以更新之后读线程立马可以读到最新数据,但是由于还没有到释放锁的代码,所以此时其他线程不能更新数据。
(6)CopyOnWriteArrayList设计上的优点
对CopyOnWriteArrayList是读写分离的思想,我们刚才看底层也看到读写的其实是不同的数组。
(7)我有一个问题CopyOnWriteArrayList与Collections.synchronizedList有什么区别,对于此问题找到一个【CopyOnWriteArrayList与Collections.synchronizedList的性能对比】博客还没看。链接贴在下面。
https://blog.csdn.net/yangzl2008/article/details/39456817