ArraysList是线程不安全的数据类型。如果多个线程同时访问列表实例,并且至少有一个线程在结构上修改列表,则需要在外部同步。使用Collections.sychronizedList
方法是线程安全的。
查看JDK文档,在结构上修改ArraysList的方法有
分析源码发现,在add方法中的elementData[size++] = e;
存在线程不安全的风险。
elementData与size都是全局变量,但没有进行sychronization同步处理,elementData是共享的线程不安全的mutable可变数据。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
private int size;
..................
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
}
在iterator部分存在线程不安全的风险,原因之一是iterator部分直接使用了ArraysList的add方法ArrayList.this.add(i, e);
,但没有进行sychronization同步处理。
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
.......................
}
/**
* An optimized version of AbstractList.ListItr
*/
private class ListItr extends Itr implements ListIterator<E> {
........................
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
总结
本文通过add和Iterator入手分析ArraysList线程不安全的原因,可能不够全面,欢迎补充,欢迎指正!
转载:https://blog.csdn.net/JAck_chen0309/article/details/105154164
查看评论