目錄
直接看示例
public class ArrayListTest { private static List<String> threadList = new ArrayList<String>();
public static void main(String[] args) { try { testWriteArrayListError(); } catch (Exception e) { e.printStackTrace(); } } 原文:https://blog.csdn.net/lan861698789/article/details/81697409 /** * @Title: arraylist * @author: crazyJava * @Description: 測試併發對arraylist的影響 * @throws Exception * @return void */ private static void testWriteArrayListError() throws Exception {
Runnable writeR = new Runnable() { public void run() { threadList.add(Thread.currentThread().getName()); } };
for (int i = 0; i < 1000; i++) { Thread t = new Thread(writeR, i + ""); t.start(); }
// 等待子線程執行完 Thread.sleep(2000);
System.out.println(threadList.size()); // 輸出list中的值 for (int i = 0; i < threadList.size(); i++) { System.out.println("index:" +i + "->" + threadList.get(i)); } } } |
結果1.併發導致數據丟失
結果2.併發導致插入null
996 index:0->0 index:1->1 ...... index:107->485 index:108->354 index:109->null index:110->479 |
結果3.併發導致數組越界
分析:
以添加爲例,代碼(JDK1.7):
原文:https://blog.csdn.net/lan861698789/article/details/81697409
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!!//代碼1 elementData[size++] = e;//代碼2 return true; } private void ensureExplicitCapacity(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) {//第一次add時候,初始化容量大小爲: 默認值10 or minCapacity minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } modCount++; if (minCapacity - elementData.length > 0) {//判斷是否需要擴容//代碼3 int oldCapacity = elementData.length;//現在容量大小 int newCapacity = oldCapacity + (oldCapacity >> 1);//擴容原來容量的1.5倍 if (newCapacity - minCapacity < 0) //如果擴容後還是不能滿足,則當前容量設置爲 需要插入的大小 newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);//數組的擴容 } } |
黃色部分(代碼2)可拆分爲兩條語句:
elementData[size] = e; size ++; |
結果1和2原因:
假設初始size爲0,elementData爲空。
當線程A執行完elementData[size] = e;還未執行size++就停止了,此時,size=0; elementData[0]放的是A的value,
然後線程B正常完成一個add操作;此時size=1,elementData[0]裏面放的是B的value,把A的value給覆蓋了。
然後B繼續執行size++; 此時,size=2了。數據結構如下:
結果3原因:
假設初始化size爲9,elementData.length也爲10,這裏處於要擴容的臨界點。
當線程A執行完代碼1(ensureCapacityInternal(size + 1)),後暫停了。此時未擴容。
然後線程B也執行代碼1(ensureCapacityInternal(size + 1)),也沒有擴容,然後繼續往後正常執行。此時size變爲了10了。
然後線程A繼續執行代碼2,size先變爲11,然後在賦值給elementData[10],此時就會拋出數據越界錯誤。
原文:https://blog.csdn.net/lan861698789/article/details/81697409