成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 8 中 HashMap 的性能提升

開發 后端
HashMap是一個高效通用的數據結構,它在每一個Java程序中都隨處可見。先來介紹些基礎知識。你可能也知 道,HashMap使用key的hashCode()和equals()方法來將值劃分到不同的桶里。桶的數量通常要比map中的記錄的數量要稍大,這樣 每個桶包括的值會比較少(最好是一個)。

HashMap是一個高效通用的數據結構,它在每一個Java程序中都隨處可見。先來介紹些基礎知識。你可能也知 道,HashMap使用key的hashCode()和equals()方法來將值劃分到不同的桶里。桶的數量通常要比map中的記錄的數量要稍大,這樣 每個桶包括的值會比較少(最好是一個)。當通過key進行查找時,我們可以在常數時間內迅速定位到某個桶(使用hashCode()對桶的數量進行取模) 以及要找的對象。

這些東西你應該都已經知道了。你可能還知道哈希碰撞會對hashMap的性能帶來災難性的影響。如果多個hashCode()的值落到同一個桶內的 時候,這些值是存儲到一個鏈表中的。最壞的情況下,所有的key都映射到同一個桶中,這樣hashmap就退化成了一個鏈表——查找時間從O(1)到 O(n)。我們先來測試下正常情況下hashmap在Java 7和Java 8中的表現。為了能完成控制hashCode()方法的行為,我們定義了如下的一個Key類:

  1. class Key implements Comparable<Key> {  
  2. private final int value;  
  3. Key(int value) {  
  4. this.value = value;  
  5. }  
  6. @Override 
  7. public int compareTo(Key o) {  
  8. return Integer.compare(this.value, o.value);  
  9. }  
  10. @Override 
  11. public boolean equals(Object o) {  
  12. if (this == o) return true;  
  13. if (o == null || getClass() != o.getClass())  
  14. return false;  
  15. Key key = (Key) o;  
  16. return value == key.value;  
  17. }  
  18. @Override 
  19. public int hashCode() {  
  20. return value;  
  21. }  

Key類的實現中規中矩:它重寫了equals()方法并且提供了一個還算過得去的hashCode()方法。為了避免過度的GC,我將不可變的Key對象緩存了起來,而不是每次都重新開始創建一遍:

  1. class Key implements Comparable<Key> {  
  2. public class Keys {  
  3. public static final int MAX_KEY = 10_000_000;  
  4. private static final Key[] KEYS_CACHE = new Key[MAX_KEY];  
  5. static {  
  6. for (int i = 0; i < MAX_KEY; ++i) {  
  7. KEYS_CACHE[i] = new Key(i);  
  8. }  
  9. }  
  10. public static Key of(int value) {  
  11. return KEYS_CACHE[value];  
  12. }  

現在我們可以開始進行測試了。我們的基準測試使用連續的Key值來創建了不同的大小的HashMap(10的乘方,從1到1百萬)。在測試中我們還會使用key來進行查找,并測量不同大小的HashMap所花費的時間:

  1. import com.google.caliper.Param;  
  2. import com.google.caliper.Runner;  
  3. import com.google.caliper.SimpleBenchmark;  
  4. public class MapBenchmark extends SimpleBenchmark {  
  5. private HashMap<Key, Integer> map;  
  6. @Param 
  7. private int mapSize;  
  8. @Override 
  9. protected void setUp() throws Exception {  
  10. map = new HashMap<>(mapSize);  
  11. for (int i = 0; i < mapSize; ++i) {  
  12. map.put(Keys.of(i), i);  
  13. }  
  14. }  
  15. public void timeMapGet(int reps) {  
  16. for (int i = 0; i < reps; i++) {  
  17. map.get(Keys.of(i % mapSize));  
  18. }  
  19. }  

gfbdbnbtrbtrbgnrnjytk1

有意思的是這個簡單的HashMap.get()里面,Java 8比Java 7要快20%。整體的性能也相當不錯:盡管HashMap里有一百萬條記錄,單個查詢也只花了不到10納秒,也就是大概我機器上的大概20個CPU周期。 相當令人震撼!不過這并不是我們想要測量的目標。

假設有一個很差勁的key,他總是返回同一個值。這是最糟糕的場景了,這種情況完全就不應該使用HashMap:

  1. class Key implements Comparable<Key> {  
  2. //...  
  3. @Override 
  4. public int hashCode() {  
  5. return 0;  
  6. }  

erhrthtrhtrjhrdnjliuzsert2

Java 7的結果是預料中的。隨著HashMap的大小的增長,get()方法的開銷也越來越大。由于所有的記錄都在同一個桶里的超長鏈表內,平均查詢一條記錄就需要遍歷一半的列表。因此從圖上可以看到,它的時間復雜度是O(n)。

不過Java 8的表現要好許多!它是一個log的曲線,因此它的性能要好上好幾個數量級。盡管有嚴重的哈希碰撞,已是最壞的情況了,但這個同樣的基準測試在JDK8中的時間復雜度是O(logn)。單獨來看JDK 8的曲線的話會更清楚,這是一個對數線性分布:

hbhtrtyjyuswewef3

為什么會有這么大的性能提升,盡管這里用的是大O符號(大O描述的是漸近上界)?其實這個優化在JEP-180中已經提到了。如果某個桶中的記錄過 大的話(當前是TREEIFY_THRESHOLD = 8),HashMap會動態的使用一個專門的treemap實現來替換掉它。這樣做的結果會更好,是O(logn),而不是糟糕的O(n)。它是如何工作 的?前面產生沖突的那些KEY對應的記錄只是簡單的追加到一個鏈表后面,這些記錄只能通過遍歷來進行查找。但是超過這個閾值后HashMap開始將列表升 級成一個二叉樹,使用哈希值作為樹的分支變量,如果兩個哈希值不等,但指向同一個桶的話,較大的那個會插入到右子樹里。如果哈希值相等,HashMap希 望key值最好是實現了Comparable接口的,這樣它可以按照順序來進行插入。這對HashMap的key來說并不是必須的,不過如果實現了當然最 好。如果沒有實現這個接口,在出現嚴重的哈希碰撞的時候,你就并別指望能獲得性能提升了。

這個性能提升有什么用處?比方說惡意的程序,如果它知道我們用的是哈希算法,它可能會發送大量的請求,導致產生嚴重的哈希碰撞。然后不停的訪問這些 key就能顯著的影響服務器的性能,這樣就形成了一次拒絕服務攻擊(DoS)。JDK 8中從O(n)到O(logn)的飛躍,可以有效地防止類似的攻擊,同時也讓HashMap性能的可預測性稍微增強了一些。我希望這個提升能最終說服你的 老大同意升級到JDK 8來。

測試使用的環境是:Intel Core i7-3635QM @ 2.4 GHz,8GB內存,SSD硬盤,使用默認的JVM參數,運行在64位的Windows 8.1系統 上。

原文出處: Tomasz Nurkiewicz   譯文出處: deepinmind

責任編輯:林師授 來源: deepinmind
相關推薦

2015-01-06 09:59:03

2022-07-10 22:29:42

AtomicJDK項目

2015-02-05 09:47:52

Web性能Web開發

2021-12-29 11:06:25

Java代碼技巧

2023-05-12 13:21:12

JMHJava程序

2011-09-16 10:19:41

2009-03-30 09:10:53

微軟瀏覽器IE8

2016-09-12 14:33:20

javaHashMap

2013-05-22 09:38:03

GoGo語言Go性能

2014-07-31 09:28:09

ASP.NETWeb API

2012-03-12 13:54:56

ASP.NET

2015-02-04 09:19:03

Web優化

2021-11-25 22:54:23

人工智能機器學習技術

2020-10-27 08:24:01

Java

2023-05-22 14:19:48

索引Iceberg

2021-12-02 07:02:16

API性能設計

2024-11-18 19:00:29

2020-08-17 10:30:35

Web前端自適應加載

2011-11-30 21:59:41

ibmdwDojo

2011-02-22 09:40:18

HashMap
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91日韩| 手机av网| 久久久久久a| 动漫www.被爆羞羞av44 | 精品欧美| 超碰在线影院 | 欧美日韩激情 | 黄色av网站免费看 | 狠狠综合久久av一区二区小说 | 欧产日产国产精品国产 | 日韩视频在线播放 | 中文字幕一区二区在线观看 | 国产一区二区三区在线看 | 黄色在线观看国产 | 国产99久久精品一区二区永久免费 | 亚洲一区国产 | 欧美一区二区在线观看视频 | 国产不卡一 | 99精品视频在线观看免费播放 | 欧美亚洲在线 | 久久久久久高清 | 亚洲视频免费在线看 | 九九av| 九九伊人sl水蜜桃色推荐 | 国产精品久久久久久一区二区三区 | 在线免费观看黄色 | 九九热在线视频观看这里只有精品 | 一区二区三区av | 福利国产 | 国产精品久久久久久妇女 | 精品国产第一区二区三区 | 国产三级网站 | 在线精品亚洲欧美日韩国产 | 韩国av一区二区 | 欧美激情免费在线 | 91视视频在线观看入口直接观看 | 中文字幕1区2区3区 亚洲国产成人精品女人久久久 | 欧美视频一区 | 九一国产精品 | 精品国产一级 | av在线免费观看网址 |