1,概述
Arraylist是一个有序的集合,底层是基于数组实现的。所以查询速度快,但是增删相对较慢。而且是一个非线程安全的集合。下面我们结合源码看一下为什么非线程安全。
2,源码分析:
public boolean add(E e) {
/**
* 添加一个元素时,做了如下两步操作
* 1.判断列表的capacity容量是否足够,是否需要扩容
* 2.真正将元素放在列表的元素数组里面
*/
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal()这个方法的详细代码我们可以暂时不看,它的作用就是判断如果将当前的新元素加到列表后面,列表的elementData数组的大小是否满足,如果size + 1的这个需求长度大于了elementData这个数组的长度,那么就要对这个数组进行扩容。
由此看到add元素时,实际做了两个大的步骤:
1.判断elementData数组容量是否满足需求
2.在elementData对应位置上设置值
这样也就出现了第一个导致线程不安全的隐患,在多个线程进行add操作时可能会导致elementData数组越界。具体逻辑如下:
1⃣️,列表大小为9,即size=9
2⃣️,线程A开始进入add方法,这时它获取到size的值为9,调用ensureCapacityInternal方法进行容量判断。
3⃣️,线程B此时也进入add方法,它获取到size的值也为9,也开始调用ensureCapacityInternal方法。
4⃣️, 线程A发现需求大小为10,而elementData的大小就为10,可以容纳。于是它不再扩容,返回。
5⃣️,线程B也发现需求大小为10,也可以容纳,返回。 线程A开始进行设置值操作, elementData[size++] = e
6⃣️,操作。此时size变为10。 线程B也开始进行设置值操作,它尝试设置elementData[10] =e,而elementData没有进行过扩容,它的下标最大为9。于是此时会报出一个数组越界的异常ArrayIndexOutOfBoundsException
.另外第二步 elementData[size++] = e 设置值的操作同样会导致线程不安全。从这儿可以看出,这步操作也不是一个原子操作,它由如下两步操作构成:
elementData[size] = e;
size = size + 1;
3,解决方案:
1,vector 或着 SynchronizedList
SynchronizedList的兼容性比vector更好,但两者都是所有方法带同步锁,读写多的情况下效率非常低。所以并不是很好的方案。
2,java.util.concurrent.CopyOnWriteArrayList
CopyOnWrite(简称:COW):即复制再写入,jdk1.5后加入的,就是在添加元素的时候,先把原 List 列表复制一份,再添加新的元素。
先来看下它的 add 方法源码:
public boolean add(E e) {
// 加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 获取原始集合
Object[] elements = getArray();
int len = elements.length;
// 复制一个新集合
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
// 替换原始集合为新集合
setArray(newElements);
return true;
} finally {
// 释放锁
lock.unlock();
}
}
添加元素时,先加锁,再进行复制替换操作,最后再释放锁。
再来看下它的 get 方法源码:
private E get(Object[] a, int index) {
return (E) a[index];
}
public E get(int index) {
return get(getArray(), index);
}
可以看到,获取元素并没有加锁。
这样做的好处是,在高并发情况下,读取元素时就不用加锁,写数据时才加锁,大大提升了读取性能。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/10834.html