我正在学习Java多线程。我写了一小段代码并产生了一些我无法理解的输出..请帮助解释一下。 发布下面的代码。
package com.java.learn;
import java.util.ArrayList;
import java.util.List;
public class ListTestWithMultiThread {
static final List<Integer> list = new ArrayList<Integer>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
list.add(Integer.valueOf(i));
}
System.out.println("List size at thread 0 : " + list.size());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 101; i <= 200; i++) {
list.add(Integer.valueOf(i));
}
System.out.println("List size at thread 1 : " + list.size());
}
}).start();
}
}
各种运行中的一些o/p: 线程 0 处的列表大小:134 线程 1 处的列表大小:200
Exception in thread "Thread-1" List size at thread 0 : 101
java.lang.ArrayIndexOutOfBoundsException: 17
at java.util.ArrayList.add(Unknown Source)
at com.java.learn.ListTestWithMultiThread$2.run(ListTestWithMultiThread.java:25)
at java.lang.Thread.run(Unknown Source)
List size at thread 0 : 106
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 58
at java.util.ArrayList.add(Unknown Source)
at com.java.learn.ListTestWithMultiThread$2.run(ListTestWithMultiThread.java:25)
at java.lang.Thread.run(Unknown Source)
最佳答案
您正在访问的数据结构( list
)不是为并行并发访问而设计的,并且没有对其进行保护(例如通过 synchronized
)。这最终会破坏数据结构的内部结构,导致奇怪的行为,比如你得到的异常。
这里有两种方法来保护它:
- 使用并发数据结构:
List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
使用
synchronized
保护列表:synchronized(list) { list.add(Integer.valueOf(i)); }
编辑:既然您要求这样做,那么 ArrayList
的方式如下:可能会被损坏。
安ArrayList
由一个数组支持,当列表增长时,该数组必须调整大小。这里调整大小意味着分配一个更大的新数组,并将旧数组的内容复制到新数组。以下是 the code 的部分内容这样做是这样的:
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
...
elementData = Arrays.copyOf(elementData, newCapacity);
现在想象一下:线程 A 开始调整数组大小,计算新容量并开始复制第 4 行中的数据。但在它可以将新数组的引用复制到 elementData
之前无论出于何种原因,它都会停止(这种情况经常发生)。现在线程 B 开始调整数组大小并完成。然后它会向列表中插入更多值并再次调整数组大小并完成。线程 B 现在假设该列表对于新值来说足够大,但在插入该值之前,线程 A 唤醒并覆盖 elementData
以及对其创建的较小数组的引用。线程 B 现在尝试将值插入到较小的数组中并获得 ArrayIndexOutOfBoundsException
。这一切都不太可能发生,但正如您所见,它可能会发生。
关于Java 多线程行为解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35519352/