基準測試了 ArrayList 和 LinkedList ,發現咱們一直用 ArrayList 也是沒什麼問題的

ArrayList 應該是 Java 中最經常使用的集合類型了,以致於咱們說到集合就會天然而然的想到 ArrayList。不少同窗都沒有用過除了 ArrayList 以外的其餘集合,甚至於都已經忘了除了 ArrayList 以外的其餘集合,例如 LinkedList、Vector 等。java

那麼咱們平時只用 ArrayList 是否是正確呢,我既然知道了 LinkedList、Vector ,是否是也要用一下它呢,那麼什麼狀況下用呢。編程

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

那麼如今就來比較一下 ArrayList 和 LinkedList,都說插入、刪除操做多的話用 LinkedList,插入操做多的話用 ArrayList,產生這種說法的大體依據以下。安全

ArrayList多線程

內部是用 Object 數組做爲存儲結構,數組是內存中連續的內存空間,而且繼承了 RandomAccess接口,因此能夠實現元素的快速訪問。但若是不是在末尾插入元素的話,須要拷貝插入位置以後的元素。dom

LinkedList性能

內部本身實現的 Node 鏈表,每一個節點都指明瞭上一節點和下一節點, 因此不要求內存連續,而且插入數據只須要修改上一節點和下一節點的指針便可。可是訪問元素須要遍歷查找,因此查詢元素較慢。測試

真的是這樣嗎?下面我作了一系列的測試,來看一下真實的狀況。線程

插入數據

分別從頭部、尾部和隨機位置插入數據,初始的列表長度分別爲 十、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 種方式遍歷的性能



不管是1w、100w、1000w ,這五種方式的性能排名都是基本穩定的。原始 for 循環最優,forEach 方式最差。

LinkedList 這 5 種方式遍歷的性能



不管是1w、100w、1000w ,這五種方式的性能排名都是基本穩定的。和 ArrayList 類似,都是原始 for 循環最優,forEach 方式最差,其餘三種方式相差不大。

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



觀察發現,迭代器方式、stream 方式、加強 for 循環這三種方式,ArrayList 的性能基本上都要優於 LinkedList,而最原始的 for 循環方式,直到列表長度達到了 1000w,仍然是 LinkedList 優於 ArrayList。

LinkedList 只有在頭部插入和刪除數據頻繁的時候纔有優點,可是能找到這種應用場景彷佛也不容易找到。如此看來,咱們在程序中用到列表就隨手 new 一個 ArrayList 倒也頗有道理。

不要吝惜你的「推薦」呦

本文中的測試使用 JMH 基準測試完成的,圖表是用 Excel 作的,若是須要源碼和 Excel 文件,請在公衆號內回覆關鍵詞 「jmh」

歡迎關注,不按期更新本系列和其餘文章
古時的風箏 ,進入公衆號能夠加入交流羣

相關文章
相關標籤/搜索