Map和List性能測試

Map mm=new HashMap(100);
   List l=new ArrayList(100);
   long l1=System.currentTimeMillis();
   for(int i=0;i<1000000;i++){
    mm.put(i, i);
   }
   System.out.println("put map="+(System.currentTimeMillis()-l1));
   l1=System.currentTimeMillis();
   for(int i=0;i<1000000;i++){
    l.add(i);
   }
   System.out.println("add list="+(System.currentTimeMillis()-l1));
   l1=System.currentTimeMillis();
   for(int i=0;i<1000000;i++){
    mm.get(i);
   }
   System.out.println("get map="+(System.currentTimeMillis()-l1));
   l1=System.currentTimeMillis();
   for(int i=0;i<1000000;i++){
    l.get(i);
   }
   System.out.println("get list="+(System.currentTimeMillis()-l1));
   java

put map=1031
add list=157
get map=93
get list=16數組

竟然性能相差這大!!安全

ps:這是基本單線程測試的服務器

 

 付多線程版本的Map和List測試,介紹多線程


ConcurrentHashMap併發

util.concurrent 包中的 ConcurrentHashMap 類(也將出如今JDK 1.5中的 java.util.concurrent 包中)是對 Map 的線程安全的實現,比起 synchronizedMap 來,它提供了好得多的併發性。多個讀操做幾乎總能夠併發地執行,同時進行的讀和寫操做一般也能併發地執行,而同時進行的寫操做仍然能夠不時地併發進行(相關的類也提供了相似的多個讀線程的併發性,可是,只容許有一個活動的寫線程) 。ConcurrentHashMap 被設計用來優化檢索操做;實際上,成功的 get() 操做完成以後一般根本不會有鎖着的資源。要在不使用鎖的狀況下取得線程安全性須要必定的技巧性,而且須要對Java內存模型(Java Memory Model)的細節有深刻的理解。 ConcurrentHashMap 實現,加上 util.concurrent 包的其餘部分,已經被研究正確性和線程安全性的併發專家所正視。在下個月的文章中,咱們將看看 ConcurrentHashMap 的實現的細節。性能

ConcurrentHashMap 經過稍微地鬆弛它對調用者的承諾而得到了更高的併發性。檢索操做將能夠返回由最近完成的插入操做所插入的值,也能夠返回在步調上是併發的插入操做所添加的值(可是決不會返回一個沒有意義的結果)。由 ConcurrentHashMap.iterator() 返回的 Iterators 將每次最多返回一個元素,而且決不會拋出 ConcurrentModificationException 異常,可是可能會也可能不會反映在該迭代器被構建以後發生的插入操做或者移除操做。在對集合進行迭代時,不須要表範圍的鎖就能提供線程安全性。在任何不依賴於鎖整個表來防止更新的應用程序中,可使用 ConcurrentHashMap 來替代 synchronizedMapHashtable測試

上述改進使得 ConcurrentHashMap 可以提供比 Hashtable 高得多的可伸縮性,並且,對於不少類型的公用案例(好比共享的cache)來講,還不用損失其效率。優化

好了多少?spa

表 1對 HashtableConcurrentHashMap 的可伸縮性進行了粗略的比較。在每次運行過程當中, n 個線程併發地執行一個死循環,在這個死循環中這些線程從一個 Hashtable 或者 ConcurrentHashMap 中檢索隨機的key value,發如今執行 put() 操做時有80%的檢索失敗率,在執行操做時有1%的檢索成功率。測試所在的平臺是一個雙處理器的Xeon系統,操做系統是Linux。數據顯示了10,000,000次迭代以毫秒計的運行時間,這個數據是在將對 ConcurrentHashMap的 操做標準化爲一個線程的狀況下進行統計的。您能夠看到,當線程增長到多個時, ConcurrentHashMap 的性能仍然保持上升趨勢,而 Hashtable 的性能則隨着爭用鎖的狀況的出現而當即降了下來。

比起一般狀況下的服務器應用,此次測試中線程的數量看上去有點少。然而,由於每一個線程都在不停地對錶進行操做,因此這與實際環境下使用這個表的更多數量的線程的爭用狀況基本等同。

表 1.Hashtable 與 ConcurrentHashMap在可伸縮性方面的比較

線程數 ConcurrentHashMap Hashtable
1 1.00 1.03
2 2.59 32.40
4 5.58 78.23
8 13.21 163.48
16 27.58 341.21
32 57.27 778.41



CopyOnWriteArrayList

在那些遍歷操做大大地多於插入或移除操做的併發應用程序中,通常用 CopyOnWriteArrayList 類替代 ArrayList 。若是是用於存放一個偵聽器(listener)列表,例如在AWT或Swing應用程序中,或者在常見的JavaBean中,那麼這種狀況很常見(相關的 CopyOnWriteArraySet 使用一個 CopyOnWriteArrayList 來實現 Set 接口)。

若是您正在使用一個普通的 ArrayList 來存放一個偵聽器列表,那麼只要該列表是可變的,並且可能要被多個線程訪問,您就必需要麼在對其進行迭代操做期間,要麼在迭代前進行的克隆操做期間,鎖定整個列表,這兩種作法的開銷都很大。當對列表執行會引發列表發生變化的操做時, CopyOnWriteArrayList 並非爲列表建立一個全新的副本,它的迭代器確定可以返回在迭代器被建立時列表的狀態,而不會拋出 ConcurrentModificationException 。在對列表進行迭代以前沒必要克隆列表或者在迭代期間鎖定列表,由於迭代器所看到的列表的副本是不變的。換句話說, CopyOnWriteArrayList 含有對一個不可變數組的一個可變的引用,所以,只要保留好那個引用,您就能夠得到不可變的線程安全性的好處,並且不用鎖定列表。

相關文章
相關標籤/搜索