容器中的List在我們日常開發中,比較常用,而且也是面試的必考題,下面我們來說下List家族的各種實作;
1.ArrayList
ArrayList底層是數組實作,順序插入,可以通過下标查找元素,速度很快,插入和删除元素很慢,非線程安全,比如在多線層的情況下add(),會出現覆寫情況;
容易出現問題的地方在于,elementData[size++] = e;首先把元素指派給數組,然後長度增加,當兩個線程同時增加元素時,線程1拿到時間片指派elementData[size] = 1,執行後失去時間片,線程2獲得時間片,elementData[size] = 2,這樣線程1的值就被線程給覆寫了,長度兩次增加變成2,實際上第2個值是null,這樣就出現了問題;同時周遊時需改也存在java.util.ConcurrentModificationException異常;
2.Vector Vector底層也是數組,它和ArrayList的差別在于add、set、get方等法上都加了synchronized關鍵字,這樣就保證了多線程下的線程安全問題,但是效率不如ArrayList;
3.SynchronizedList SynchronizedList是容器工具包提供的包裝同步類,List<String> stringList = Collections.synchronizedList(list);看下面的代碼,他在set、get等方法内部加了同步代碼塊,synchronized (mutex) 鎖住了傳入的對象,但是效率沒有太大的改變。
複制
4.CopyOnWriteArrayList
CopyOnWriteArrayList是今天的主角,它是一個實作讀寫分離的容器,add時通過一個非公平鎖加鎖,然後複制現有數組為一個新的數組,再把新加入的元素添加到新數組中,把數組指針指向新數組,這樣寫輸入保證了線程安全問題,使用可重入鎖的非公平鎖效率很高,讀資料的時候,讀現有的數組,不用加鎖,效率提升很多,缺點是每次寫入都要複制一個新的數組,會造成記憶體浪費,垃圾回收頻繁等,适合讀多寫少的場景。