都說ArrayList是線程不安全的,那為什么不安全呢。根據官方提供的源碼,
我是這樣理解的,ArrayList的成員方法都不是原子操作的,比如add(E)方法,該方法是在集合的尾部加入一個一個元素.
add(E)源碼如下:
/** * 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; }
網上的思路大致是這樣的:
add(E)操作有兩步,1>尾部添加元素 2>修改集合的容量 ,容量加一。
因為是兩步,所以必然存在A走完了第一步驟,比如將"張三"放在了index=10的地方,此時還沒來得及修改容量,
此時A被掛起,線程B切進來了,因為總容量沒變,所以繼續在尾部添加,於是index=10的位置被B線程的值占用了,
也就是A添加的值操作就被B沖了,后面的操作繼續,A修改容量加1,B修改容量加1。此時容量增加了2,元素只加入了1,所以線程不安全
這樣理解沒問題,只是根據源碼,先執行的是修改容量,然后才是添加元素。這該怎么解釋啊?
先修改了容量,哪怕A被暫停了,B執行了,那么結果也是容量增加了2,哪怕后續的操作發生異常,那也沒問題啊,因為ArrayList是容許空值得啊!!
求解啊,各位大神
繼續研究,更讓人痛苦,下面是測試代碼:
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,但是運行結果不是的,
所以說,的確是線程不安全的,但是我理解不透啊!!!
求指點,路過的各路大神