RaM*_*abU 3 java concurrency multithreading arraylist
我已经通过非线程安全对象(这里是ArrayList
)运行以下代码来运行多个线程:
import java.time.LocalDateTime;
import java.util.List;
import java.util.ArrayList;
public class A implements Runnable {
String name;
static List<Integer> list = new ArrayList();
private static Object lock = new Object();
A(String name) {
this.name = name;
}
@Override
public void run() {
for(int i = 1; i <= 1000; i++) {
list.add(i);
}
System.out.println(list.size());
}
}
Run Code Online (Sandbox Code Playgroud)
我期待这段代码只是为了产生错误的答案,因为ArrayList
它不是线程安全的.但相反,我得到这个错误:
Exception in thread "Thread-1" 1003
2401
2799
3799
java.lang.ArrayIndexOutOfBoundsException: 109
at java.util.ArrayList.add(Unknown Source)
at threads.A.run(A.java:16)5123
at java.lang.Thread.run(Unknown Source)
Exception in thread "Thread-5" java.lang.ArrayIndexOutOfBoundsException: 4164
at java.util.ArrayList.add(Unknown Source)
at threads.A.run(A.java:16)
at java.lang.Thread.run(Unknown Source)
6123
Run Code Online (Sandbox Code Playgroud)
任何人都可以向我解释导致这个特定错误的原因是什么?
好吧,您在多线程环境中使用非线程安全的集合而没有任何同步.
让我们检查add
一下获得异常的方法:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
Run Code Online (Sandbox Code Playgroud)
当多个线程同时调用此方法时,很可能会ensureCapacityInternal(size + 1)
验证是否有足够的空间容纳1个新元素,但是多个线程会尝试同时添加一个元素,因此elementData[size++]
会抛出ArrayIndexOutOfBoundsException
一些元素.
ArrayList
不是一个线程安全的类.
元素的底层存储Object[]
是一个数组.任何数组都需要在编译时预定义的内存中的分配空间.但是,当ArrayList
"想要"添加新元素(超出底层数组绑定)时,必须完成几件事(不知情).底层数组获得新的(增加的)长度.旧的数组的每个元素被复制到新的数组,并然后加入新的元素.因此,在多线程环境中使用a 时,可以预期ArrayIndexOutOfBoundsException
异常ArrayList
.
您添加的元素太快,因此ArrayList#add() -> grow() -> newCapacity()
无法计算为所有元素分配内存的正确容量.
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
Run Code Online (Sandbox Code Playgroud)
在某些时候,s == elementData.length
内部条件ArrayList#add
表示有一个新元素的空间A
.紧接着其他线程将其元素放入列表中.现在不存在用于空间A
和elementData[s] = e;
抛出异常.
归档时间: |
|
查看次数: |
574 次 |
最近记录: |