併發下的ArrayList錯誤分析

目錄

結果1.併發導致數據丟失

結果2.併發導致插入null

結果3.併發導致數組越界

分析:


直接看示例

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章