都說ArrayList是線程不安全的,那爲何不安全呢。根據官方提供的源碼,java
我是這樣理解的,ArrayList的成員方法都不是原子操做的,好比add(E)方法,該方法是在集合的尾部加入一個一個元素.安全
add(E)源碼以下:app
/** * 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; }
網上的思路大體是這樣的:ide
add(E)操做有兩步,1>尾部添加元素 2>修改集合的容量 ,容量加一。測試
由於是兩步,因此必然存在A走完了第一步驟,好比將"張三"放在了index=10的地方,此時還沒來得及修改容量,this
此時A被掛起,線程B切進來了,由於總容量沒變,因此繼續在尾部添加,因而index=10的位置被B線程的值佔用了,spa
也就是A添加的值操做就被B衝了,後面的操做繼續,A修改容量加1,B修改容量加1。此時容量增長了2,元素只加入了1,因此線程不安全線程
這樣理解沒問題,只是根據源碼,先執行的是修改容量,而後纔是添加元素。這該怎麼解釋啊?blog
先修改了容量,哪怕A被暫停了,B執行了,那麼結果也是容量增長了2,哪怕後續的操做發生異常,那也沒問題啊,由於ArrayList是允許空值得啊!!ci
求解啊,各位大神
繼續研究,更讓人痛苦,下面是測試代碼:
package sourceCode.ArrayList; import java.util.ArrayList; public class arrayListTest implements Runnable { private ArrayList<Integer> arry = null; public arrayListTest(ArrayList<Integer> arry) { this.arry = arry; } @Override public void run() { for (int i = 0; i < 10; i++) { arry.add(1); } System.out.println(arry.size()); } public static void main(String[] args) { ArrayList<Integer> a = new ArrayList<Integer>(); for (int i = 0; i < 100; i++) { new Thread(new arrayListTest(a)).start(); } } }
解讀:這例子也不是我寫的。很好理解,100個線程,每一個線程向集合中添加10個元素,按理最終集合容量應該是1000,可是運行結果不是的,
因此說,的確是線程不安全的,可是我理解不透啊!!!
求指點,路過的各路大神