线程安全CopyOnWriteArrayList
ArrayList 线程不安全问题
ArrayList 底层的数据结构其实是数组结构。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
我们来看一下 ArrayList 的 add 方法源码,上面的代码主要做了两步操作,判断当前 size+1 是否超过了数组长度和将当前数据放到数组的当前 size+1 的下标中。
这里就体现出线程不安全的情况了,在 ensureCapacityInternal(size + 1); 这步操作时,如果是多线程的情况下,如果数组大小为10,此时的 size 为9,那么线程 A 首先判断 size+1 不会导致数组下标越界,然后挂起。随后线程 B 也走到这一步发现不需要扩容,这时候执行完赋值方法后,size 大小为10了。此时线程A开始赋值,就会导致数组下标越界异常。
另外一种情况就是在 elementData[size++] = e; 这步操作的时候。我们为了好理解可以把这行代码拆分为如下代码:
elementData[size] = e;
size++;
我们发现这行代码其实并不是一个原子性的操作。它是首先将值新增到当前size位置,然后进行 size++。这个时候就会出现值被覆盖的问题。首先线程 A 将值新增到当前 size 后,在还未进行 size++ 的时候,线程 B 也将值新增到了当前的 size,此时就会造成线程A新增的值被覆盖。
LinkedList 线程不安全问题
LinkedList 的底层数据结构为双向链表,每个节点存储着数据值以及前继指针和后继指针的指向地址值。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
This chapter requires login to view full content. You are viewing a preview.
Login to View Full Content