1.为什么arrarlist线程不安全?
我们点开arraylist的add方法可以看见,add方法上是没有synchronized方法的(当然也没有添加lock),因此arraylist是线程不安全的
由于arratlist底层是一个数组,在我们新增一个元素时,后进行数组扩容,也就会调用源码中的grow()函数进行数组的扩容,但在多线程的情况下,会出现同时扩容同一个数量的数组,就会抛出ConcurrentModificationException异常问题,也就是线程不安全。
2.解决arraylist线程不安全方案
- 使用Vector方案,其中他的每个方法都添加了synchronized,因此Vector是线程安全的,但是Vector是1.0出现的解决方案,因此目前不常用这个解决方法
- 使用Collections工具类中的synchronizedList方法
List<String> list = Collections.synchronizedList(new ArrayList<>());
- CopyOnWriteArrayList(写时复制技术)
上图的解释就是,写时复制,就是当对这个list进行写的操作的时候就进行复制一份一模一样的数据,然后进行合并操作,然后读的时候就进行读合并出来新的那份数据
3.CopyOnWriteArrayList的优缺点
优点:
对于一些 读多写少的数据,这种做法的确很不错,例如配置、黑名单、物流地址等变化非常少的数据,这是一种 无锁的实现。可以帮我们实现程序更高的并发。
缺点:
这种实现只是保证数据的最终一致性,在添加到拷贝数据而还没进行替换的时候,读到的仍然是旧数据。如果对象比较大,频繁地进行替换会消耗内存,从而引发Java的GC问题,这个时候,我们应该考虑其他的容器,例如 ConcurrentHashMap。