基准測試了 ArrayList 和 LinkedList ,發現我們一直用 ArrayList 也是沒什么問題的


ArrayList 應該是 Java 中最常用的集合類型了,以至於我們說到集合就會自然而然的想到 ArrayList。很多同學都沒有用過除了 ArrayList 之外的其他集合,甚至於都已經忘了除了 ArrayList 之外的其他集合,例如 LinkedList、Vector 等。

那么我們平時只用 ArrayList 是不是正確呢,我既然知道了 LinkedList、Vector ,是不是也要用一下它呢,那么什么情況下用呢。

Vector 是線程安全的集合類型,所以僅在多線程編程的時候才考慮是否用它,凡是為了多線程設計,必然在性能上有所損失, Vector 只是在每個方法上簡單的加上 synchronized 關鍵字,所以性能損失是肯定的。

那么現在就來比較一下 ArrayList 和 LinkedList,都說插入、刪除操作多的話用 LinkedList,插入操作多的話用 ArrayList,產生這種說法的大致依據如下。

ArrayList

內部是用 Object 數組作為存儲結構,數組是內存中連續的內存空間,並且繼承了 RandomAccess接口,所以可以實現元素的快速訪問。但如果不是在末尾插入元素的話,需要拷貝插入位置之后的元素。

LinkedList

內部自己實現的 Node 鏈表,每個節點都指明了上一節點和下一節點, 所以不要求內存連續,並且插入數據只需要修改上一節點和下一節點的指針即可。但是訪問元素需要遍歷查找,所以查詢元素較慢。

真的是這樣嗎?下面我做了一系列的測試,來看一下真實的情況。

插入數據

分別從頭部、尾部和隨機位置插入數據,初始的列表長度分別為 10、1w、10w 來測試幾種插入數據的性能,以平均耗時為依據。得到的結果如下:


頭部插入數據,ArrayList 耗時明顯大於 LinkedList ,得出結論頭部插入數據 LinkedList 性能優於 ArrayList,因為在頭部位置插入數據時,ArrayList 要拷貝插入位置之后的數據,往后移動一個位置。


尾部插入數據,ArrayList 耗時小於 LinkedList,得出結論:尾部插入數據,ArrayList 性能優於 LinkedList


隨機位置是用 Random 產生的,上限是當前列表長度。可見隨機位置插入數據,ArrayList 耗時小於 LinkedList ,得出結論:多次隨機位置插入數據,平均性能 ArrayList 優於 LinkedList,注意,這里說的是多次隨機插入求的平均值。

插入數據得出以下結論
插入位置 初始列表長度10 初始列表長度1w 初始列表長度10w
頭部 LinkedList 優於 ArrayList LinkedList 優於 ArrayList LinkedList 優於 ArrayList
尾部 ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList
多次隨機位置 ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList

獲取數據

分別從頭部、尾部和隨機位置獲取數據,初始的列表長度分別為1000、10w、100w、1000w 來測試幾種獲取數據的性能,以吞吐量為判斷依據,吞吐量單位是 每毫秒內操作數。得到的結果如下:

頭部獲取數據,ArrayList 吞吐量大於 LinkedList,得出結論頭部獲取數據,ArrayList 性能優於 LinkedList


尾部獲取數據,ArrayList 吞吐量大於 LinkedList,得出結論尾部獲取數據,ArrayList 性能優於 LinkedList


多次隨機位置獲取數據,ArrayList 吞吐量大於 LinkedList,得出結論多次隨機位置獲取數據,ArrayList 性能優於 LinkedList

綜上,獲取數據操作的結論如下
獲取位置 列表長度1000 列表長度10w 列表長度100w 列表長度1000w
頭部 ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList
尾部 ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList
多次隨機位置 ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList ArrayList 優於 LinkedList

這是毋庸置疑的,實現了隨機訪問並且內部以數組形式存儲數據的 ArrayList 擁有明顯的優勢。

刪除數據

分別從頭部、尾部和隨機位置獲取數據,初始的列表長度分別為1w、100w、1000w 來測試幾種刪除數據的性能,以吞吐量為判斷依據,吞吐量單位是 每毫秒內操作數。得到的結果如下:


頭部刪除數據,LinkedList 吞吐量大於 ArrayList,得出結論:頭部刪除數據,LinkedList 性能優於 ArrayList


尾部刪除數據,ArrayList 吞吐量大於 LinkedList,得出結論:尾部刪除數據,ArrayList 性能優於 LinkedList


多次隨機位置刪除數據,ArrayList 吞吐量大於 LinkedList,得出結論:尾部刪除數據,ArrayList 性能優於 LinkedList

綜上,刪除數據操作的結論如下
獲取位置 列表長度100w 列表長度1000w
頭部 LinkedList 優於 ArrayList LinkedList 優於 ArrayList
尾部 ArrayList 優於 LinkedList ArrayList 優於 LinkedList
多次隨機位置 ArrayList 優於 LinkedList ArrayList 優於 LinkedList

遍歷數據

分別比較了 5 種遍歷方式在1000、100w、1000w 長度的列表下的性能狀況。

遍歷方式一,原始形式的 for 循環

for(int i = 0;i<x;i++){
  //do something
}

遍歷方式二,增強形式的 for 循環

for(Integer i : arrayList){
  // do something
}

遍歷方式三,迭代器方式

Iterator iterator = arrayList.iterator();
while (iterator.hasNext()){
   // do something
}

遍歷方式四,forEach 方式

arrayList.forEach(integer -> {
   // do something
});

遍歷方式五,stream 方式

正常來講,stream 后面再接 forEach 是不太正確的測試方式,一般 stream 都會配合 map、filter 等操作來進行篩選、計算等。這里為了方面測試,姑且先這個寫了。

arrayList.stream().forEach(integer -> {
   // do something
});
ArrayList 這 5 種方式遍歷的性能

LinkedList 這 5 種方式遍歷的性能

比較這五種方式下 ArrayList 和 LinkedList 的性能

LinkedList 只有在頭部插入和刪除數據頻繁的時候才有優勢,但是能找到這種應用場景似乎也不容易找到。如此看來,我們在程序中用到列表就隨手 new 一個 ArrayList 倒也很有道理。

不要吝惜你的「推薦」呦

本文中的測試使用 JMH 基准測試完成的,圖表是用 Excel 做的,如果需要源碼和 Excel 文件,請在公眾號內回復關鍵詞 「jmh」

歡迎關注,不定期更新本系列和其他文章
古時的風箏 ,進入公眾號可以加入交流群


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM