为什么当多个线程添加元素时,Arraylist的大小不正确?
threadCount = 100;
List<Object> list = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
Thread thread = new Thread(new MyThread(list, countDownLatch));
thread.start();
}
class MyThread implements Runnable {
// ......
@Override
public void run() {
for (int i = 0; i < 100; i++) {
list.add(new Object());
}
}
}
完成此程序后,列表的大小应为10000.实际上,大小可能是9950,9965或其他一些数字。为什么呢?
我知道为什么这个程序可能会引发IndexOutofBoundsException
以及为什么会有一些空值,但我只是不明白为什么大小错误。
答案 0 :(得分:3)
我只是不明白为什么尺寸错了?
由于ArrayList不是线程安全的,因此两个线程可以添加相同的索引。所以一个线程会覆盖。
答案 1 :(得分:1)
arraylist不是线程安全的,所以如果对一个arraylist对象进行任何多线程操作,结果是 undefined ,这意味着由于jvm会发生任何事情,包括但不限于错误的大小,异常,内存泄漏,如预期的那样
答案 2 :(得分:0)
很简单, 您正在对对象执行不安全的操作... 所以你无法预测稳定性...... 如果运行足够的次数,list.size()将返回10000时可能有一个实例。 为什么它不会永远回归。??答案是,因为它不是线程安全的。现在考虑添加arraylist的代码
public boolean add( E element) {
ensureCapacity(size+1); // Increments modCount!!
elementData[index] = element;
return true;
}
这里假设当线程10在“ensureCapacity”内部并且它进入睡眠状态时,其他线程(比如线程11)将会到来并且它们(线程10和11)将最终在一个地方插入2个元素。这发生在这里
答案 3 :(得分:0)
你应该参考ArrayList中的源代码。
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
ArrayList使用System.arraycopy(a, 0, newArray, 0, s)
插入元素。如果多线程正在运行,则包含元素的字段数组不是原始元素,并且大小小于预期。