Java面試題總結(2)之ArrayList 爲什麼線程不安全

我們先來看看 ArrayList 的 add 操作源碼。

  public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

ArrayList 的不安全主要體現在兩個方面。

  • 其一
elementData[size++] = e;

不是一個原子操作,是分兩步執行的。

elementData[size] = e;
size++;

單線程執行這段代碼完全沒問題,可是到多線程環境下可能就有問題了。可能一個線程會覆蓋另一個線程的值。

  1. 列表爲空 size = 0。
  2. 線程 A 執行完 elementData[size] = e;之後掛起。A 把 "a" 放在了下標爲 0 的位置。此時 size = 0。
  3. 線程 B 執行 elementData[size] = e; 因爲此時 size = 0,所以 B 把 "b" 放在了下標爲 0 的位置,於是剛好把 A 的數據給覆蓋掉了。
  4. 線程 B 將 size 的值增加爲 1。
  5. 線程 A 將 size 的值增加爲 2。
  6. 這樣子,當線程 A 和線程 B 都執行完之後理想情況下應該是 "a" 在下標爲 0 的位置,"b" 在標爲 1 的位置。而實際情況確是下標爲 0 的位置爲 "b",下標爲 1 的位置啥也沒有。
  • 其二

ArrayList 默認數組大小爲 10。假設現在已經添加進去 9 個元素了,size = 9。

  1. 線程 A 執行完 add 函數中的ensureCapacityInternal(size + 1)掛起了。
  2. 線程 B 開始執行,校驗數組容量發現不需要擴容。於是把 "b" 放在了下標爲 9 的位置,且 size 自增 1。此時 size = 10。
  3. 線程 A 接着執行,嘗試把 "a" 放在下標爲 10 的位置,因爲 size = 10。但因爲數組還沒有擴容,最大的下標才爲 9,所以會拋出數組越界異常 ArrayIndexOutOfBoundsException

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