ArrayList存在什么问题?
ArrayList是线程不安全的。
可以用Collections.synchronizedList()加全局独占锁保证线程安全,但在读多写少的情况下,多线程读之间互斥降低了系统吞吐量。
如果读与读之间不互斥,写与写、写与读才互斥,这样可以保证最大的吞吐量,这就是CopyOnWriteArrayList。
CopyOnWriteArrayList保证线程安全的原理?
1 |
|
如果用读写锁保证并发,可以保证读读之间没有阻塞等待,但有线程写数据时,读线程必须阻塞等待,这保证了每次都都可以读到最新修改的值。
CopyOnWriteArrayList牺牲了读的实时性,读操作不上锁,只在写数据时使用ReentrantLock上锁,写数据时会把原数组拷贝到新的数组中,写数据的同时再有线程读数据,读到的是之前数组的值,不保证数据实时性,只保证最终结果一致性,牺牲了数据实时性,换取了读操作没有阻塞等待。
对数据实时性要求很高的需求,不要使用CopyOnWriteArrayList。
线程1在add数据时,线程2随后get数据,不一定能获取到线程1刚add的的元素,因为线程1可能还没执行完。
CopyOnWriteArrayList存在什么问题?
- 读数据不是实时的,读的时候可能正在写数据,读不到最新的值,也不会阻塞等待,适合读多写少的场景
- 每次写数据都要复制整个数组,如果写操作频繁,会频繁触发垃圾回收,垃圾回收又会导致线程停顿,造成APP卡顿变多
CopyOnWriteArrayList适用场景?
- 高并发
- 读多写少
- 对读数据实时性要求不高
为什么没有扩容?
因为每次add元素都要拷贝数组,这个时间消耗是必须的,所以也没必要扩容了,拷贝数据到一个恰好比原数组多一个位置的新数组。
Vector有什么问题?
- Vector是线程安全的列表,底层实现也是数组,但是几乎每一个方法都加上了synchonized,多线程读操作之间会互斥,读多写少的情况下,吞吐量不高
- Vector扩容,容量是翻倍,指数增长,ArrayList只增长为原来的1.5倍,更节约空间。