JAVA流通橋

          JAVA啟發(fā)者

          統(tǒng)計

          留言簿(3)

          AJAX相關(guān)網(wǎng)址

          Eclipse相關(guān)網(wǎng)址

          Hibernate

          java相關(guān)網(wǎng)址

          LINUX相關(guān)網(wǎng)址

          webwork相關(guān)網(wǎng)址

          友好鏈接

          閱讀排行榜

          評論排行榜

          Java Map 集合類簡介

          Java Map 集合類簡介
          作者:Jack Shirazi

          了解最常用的集合類型之一 Map 的基礎(chǔ)知識以及如何針對您應(yīng)用程序特有的數(shù)據(jù)優(yōu)化 Map。

          本文相關(guān)下載:
          · Jack 的 HashMap 測試
          · Oracle JDeveloper 10g

           

          java.util 中的集合類包含 Java 中某些最常用的類。 最常用的集合類是 List 和 Map。 List 的具體實現(xiàn)包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構(gòu)建、存儲和操作任何類型對象的元素列表。 List 適用于按數(shù)值索引訪問元素的情形。

          Map 提供了一個更通用的元素存儲方法。 Map 集合類用于存儲元素對(稱作“鍵”和“值”),其中每個鍵映射到一個值。 從概念上而言,您可以將 List 看作是具有數(shù)值鍵的 Map。 而實際上,除了 List 和 Map 都在定義 java.util 中外,兩者并沒有直接的聯(lián)系。本文將著重介紹核心 Java 發(fā)行套件中附帶的 Map,同時還將介紹如何采用或?qū)崿F(xiàn)更適用于您應(yīng)用程序特定數(shù)據(jù)的專用 Map。

          了解 Map 接口和方法

          Java 核心類中有很多預(yù)定義的 Map 類。 在介紹具體實現(xiàn)之前,我們先介紹一下 Map 接口本身,以便了解所有實現(xiàn)的共同點。 Map 接口定義了四種類型的方法,每個 Map 都包含這些方法。 下面,我們從兩個普通的方法(表 1)開始對這些方法加以介紹。

          表 1: 覆蓋的方法。 我們將這 Object 的這兩個方法覆蓋,以正確比較 Map 對象的等價性。
          equals(Object o) 比較指定對象與此 Map 的等價性
          hashCode() 返回此 Map 的哈希碼

           

          Map 構(gòu)建

          Map 定義了幾個用于插入和刪除元素的變換方法(表 2)。

          表 2: Map 更新方法: 可以更改 Map 內(nèi)容。
          clear() 從 Map 中刪除所有映射
          remove(Object key) 從 Map 中刪除鍵和關(guān)聯(lián)的值
          put(Object key, Object value) 將指定值與指定鍵相關(guān)聯(lián)
          clear() 從 Map 中刪除所有映射
          putAll(Map t) 將指定 Map 中的所有映射復(fù)制到此 map

           

          盡管您可能注意到,縱然假設(shè)忽略構(gòu)建一個需要傳遞給 putAll() 的 Map 的開銷,使用 putAll() 通常也并不比使用大量的 put() 調(diào)用更有效率,但 putAll() 的存在一點也不稀奇。 這是因為,putAll() 除了迭代 put() 所執(zhí)行的將每個鍵值對添加到 Map 的算法以外,還需要迭代所傳遞的 Map 的元素。 但應(yīng)注意,putAll() 在添加所有元素之前可以正確調(diào)整 Map 的大小,因此如果您未親自調(diào)整 Map 的大?。ㄎ覀儗Υ诉M行簡單介紹),則 putAll() 可能比預(yù)期的更有效。

          查看 Map

          迭代 Map 中的元素不存在直接了當(dāng)?shù)姆椒ā?如果要查詢某個 Map 以了解其哪些元素滿足特定查詢,或如果要迭代其所有元素(無論原因如何),則您首先需要獲取該 Map 的“視圖”。 有三種可能的視圖(參見表 3

          • 所有鍵值對 — 參見 entrySet()
          • 所有鍵 — 參見 keySet()
          • 所有值 — 參見 values()

           

          前兩個視圖均返回 Set 對象,第三個視圖返回 Collection 對象。 就這兩種情況而言,問題到這里并沒有結(jié)束,這是因為您無法直接迭代 Collection 對象或 Set 對象。要進行迭代,您必須獲得一個 Iterator 對象。 因此,要迭代 Map 的元素,必須進行比較煩瑣的編碼

          Iterator keyValuePairs = aMap.entrySet().iterator();
          Iterator keys = aMap.keySet().iterator();
          Iterator values = aMap.values().iterator();
          

           

          值得注意的是,這些對象(Set、Collection 和 Iterator)實際上是基礎(chǔ) Map 的視圖,而不是包含所有元素的副本。 這使它們的使用效率很高。 另一方面,Collection 或 Set 對象的 toArray() 方法卻創(chuàng)建包含 Map 所有元素的數(shù)組對象,因此除了確實需要使用數(shù)組中元素的情形外,其效率并不高。

          我運行了一個小測試(隨附文件中的 Test1),該測試使用了 HashMap,并使用以下兩種方法對迭代 Map 元素的開銷進行了比較:

          int mapsize = aMap.size();
          Iterator keyValuePairs1 = aMap.entrySet().iterator();
          for (int i = 0; i < mapsize; i++)
          {
          Map.Entry entry = (Map.Entry) keyValuePairs1.next();
          Object key = entry.getKey();
          Object value = entry.getValue();
          ...
          }
          Object[] keyValuePairs2 = aMap.entrySet().toArray();
          for (int i = 0; i < rem; i++) {
          {
          Map.Entry entry = (Map.Entry) keyValuePairs2[i];
          Object key = entry.getKey();
          
          Profilers in Oracle JDeveloper

           

          Oracle JDeveloper 包含一個嵌入的監(jiān)測器,它測量內(nèi)存和執(zhí)行時間,使您能夠快速識別代碼中的瓶頸。 我曾使用 Jdeveloper 的執(zhí)行監(jiān)測器監(jiān)測 HashMap 的 containsKey() 和 containsValue() 方法,并很快發(fā)現(xiàn) containsKey() 方法的速度比 containsValue() 方法慢很多(實際上要慢幾個數(shù)量級?。?。 (參見圖 1圖 2,以及隨附文件中的 Test2 類)。

          Object value = entry.getValue(); ... }
          此測試使用了兩種測量方法: 一種是測量迭代元素的時間,另一種測量使用 toArray 調(diào)用創(chuàng)建數(shù)組的其他開銷。 第一種方法(忽略創(chuàng)建數(shù)組所需的時間)表明,使用已從 toArray 調(diào)用中創(chuàng)建的數(shù)組迭代元素的速度要比使用 Iterator 的速度大約快 30%-60%。 但如果將使用 toArray 方法創(chuàng)建數(shù)組的開銷包含在內(nèi),則使用 Iterator 實際上要快 10%-20%。 因此,如果由于某種原因要創(chuàng)建一個集合元素的數(shù)組而非迭代這些元素,則應(yīng)使用該數(shù)組迭代元素。 但如果您不需要此中間數(shù)組,則不要創(chuàng)建它,而是使用 Iterator 迭代元素。

           

          表 3: 返回視圖的 Map 方法: 使用這些方法返回的對象,您可以遍歷 Map 的元素,還可以刪除 Map 中的元素。
          entrySet() 返回 Map 中所包含映射的 Set 視圖。 Set 中的每個元素都是一個 Map.Entry 對象,可以使用 getKey() 和 getValue() 方法(還有一個 setValue() 方法)訪問后者的鍵元素和值元素
          keySet() 返回 Map 中所包含鍵的 Set 視圖。 刪除 Set 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)
          values() 返回 map 中所包含值的 Collection 視圖。 刪除 Collection 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)

           

          訪問元素

          表 4 中列出了 Map 訪問方法。Map 通常適合按鍵(而非按值)進行訪問。 Map 定義中沒有規(guī)定這肯定是真的,但通常您可以期望這是真的。 例如,您可以期望 containsKey() 方法與 get() 方法一樣快。 另一方面,containsValue() 方法很可能需要掃描 Map 中的值,因此它的速度可能比較慢。

          表 4: Map 訪問和測試方法: 這些方法檢索有關(guān) Map 內(nèi)容的信息但不更改 Map 內(nèi)容。
          get(Object key) 返回與指定鍵關(guān)聯(lián)的值
          containsKey(Object key) 如果 Map 包含指定鍵的映射,則返回 true
          containsValue(Object value) 如果此 Map 將一個或多個鍵映射到指定值,則返回 true
          isEmpty() 如果 Map 不包含鍵-值映射,則返回 true
          size() 返回 Map 中的鍵-值映射的數(shù)目

           

          對使用 containsKey() 和 containsValue() 遍歷 HashMap 中所有元素所需時間的測試表明,containsValue() 所需的時間要長很多。 實際上要長幾個數(shù)量級! (參見圖 1圖 2,以及隨附文件中的 Test2)。 因此,如果 containsValue() 是應(yīng)用程序中的性能問題,它將很快顯現(xiàn)出來,并可以通過監(jiān)測您的應(yīng)用程序輕松地將其識別。 這種情況下,我相信您能夠想出一個有效的替換方法來實現(xiàn) containsValue() 提供的等效功能。 但如果想不出辦法,則一個可行的解決方案是再創(chuàng)建一個 Map,并將第一個 Map 的所有值作為鍵。 這樣,第一個 Map 上的 containsValue() 將成為第二個 Map 上更有效的 containsKey()。

          圖 1
          圖 1: 使用 JDeveloper 創(chuàng)建并運行 Map 測試類

           

          圖 2
          圖 2: 在 JDeveloper 中使用執(zhí)行監(jiān)測器進行的性能監(jiān)測查出應(yīng)用程序中的瓶頸

           

          核心 Map

          Java 自帶了各種 Map 類。 這些 Map 類可歸為三種類型:

          1. 通用 Map,用于在應(yīng)用程序中管理映射,通常在 java.util 程序包中實現(xiàn)
            • HashMap
            • Hashtable
            • Properties
            • LinkedHashMap
            • IdentityHashMap
            • TreeMap
            • WeakHashMap
            • ConcurrentHashMap
          2. 專用 Map,您通常不必親自創(chuàng)建此類 Map,而是通過某些其他類對其進行訪問
            • java.util.jar.Attributes
            • javax.print.attribute.standard.PrinterStateReasons
            • java.security.Provider
            • java.awt.RenderingHints
            • javax.swing.UIDefaults
          3. 一個用于幫助實現(xiàn)您自己的 Map 類的抽象類
            • AbstractMap

           

          內(nèi)部哈希: 哈希映射技術(shù)

          幾乎所有通用 Map 都使用哈希映射。 這是一種將元素映射到數(shù)組的非常簡單的機制,您應(yīng)了解哈希映射的工作原理,以便充分利用 Map。

          哈希映射結(jié)構(gòu)由一個存儲元素的內(nèi)部數(shù)組組成。 由于內(nèi)部采用數(shù)組存儲,因此必然存在一個用于確定任意鍵訪問數(shù)組的索引機制。 實際上,該機制需要提供一個小于數(shù)組大小的整數(shù)索引值。 該機制稱作哈希函數(shù)。 在 Java 基于哈希的 Map 中,哈希函數(shù)將對象轉(zhuǎn)換為一個適合內(nèi)部數(shù)組的整數(shù)。 您不必為尋找一個易于使用的哈希函數(shù)而大傷腦筋: 每個對象都包含一個返回整數(shù)值的 hashCode() 方法。 要將該值映射到數(shù)組,只需將其轉(zhuǎn)換為一個正值,然后在將該值除以數(shù)組大小后取余數(shù)即可。 以下是一個簡單的、適用于任何對象的 Java 哈希函數(shù)

          int hashvalue = Maths.abs(key.hashCode()) % table.length;
          

           

          (% 二進制運算符(稱作模)將左側(cè)的值除以右側(cè)的值,然后返回整數(shù)形式的余數(shù)。)

          實際上,在 1.4 版發(fā)布之前,這就是各種基于哈希的 Map 類所使用的哈希函數(shù)。 但如果您查看一下代碼,您將看到

          int hashvalue = (key.hashCode() & 0x7FFFFFFF) % table.length;
          

           

          它實際上是使用更快機制獲取正值的同一函數(shù)。 在 1.4 版中,HashMap 類實現(xiàn)使用一個不同且更復(fù)雜的哈希函數(shù),該函數(shù)基于 Doug Lea 的 util.concurrent 程序包(稍后我將更詳細地再次介紹 Doug Lea 的類)。

          圖 3
          圖 3: 哈希工作原理

           

          該圖介紹了哈希映射的基本原理,但我們還沒有對其進行詳細介紹。 我們的哈希函數(shù)將任意對象映射到一個數(shù)組位置,但如果兩個不同的鍵映射到相同的位置,情況將會如何? 這是一種必然發(fā)生的情況。 在哈希映射的術(shù)語中,這稱作沖突。 Map 處理這些沖突的方法是在索引位置處插入一個鏈接列表,并簡單地將元素添加到此鏈接列表。 因此,一個基于哈希的 Map 的基本 put() 方法可能如下所示

          public Object put(Object key, Object value) {
          //我們的內(nèi)部數(shù)組是一個 Entry 對象數(shù)組
          //Entry[] table;
          //獲取哈希碼,并映射到一個索引
          int hash = key.hashCode();
          int index = (hash & 0x7FFFFFFF) % table.length;
          //循環(huán)遍歷位于 table[index] 處的鏈接列表,以查明
          //我們是否擁有此鍵項 — 如果擁有,則覆蓋它
          for (Entry e = table[index] ; e != null ; e = e.next) {
          //必須檢查鍵是否相等,原因是不同的鍵對象
          //可能擁有相同的哈希
          if ((e.hash == hash) && e.key.equals(key)) {
          //這是相同鍵,覆蓋該值
          //并從該方法返回 old 值
          Object old = e.value;
          e.value = value;
          return old;
          }
          }
          //仍然在此處,因此它是一個新鍵,只需添加一個新 Entry
          //Entry 對象包含 key 對象、 value 對象、一個整型的 hash、
          //和一個指向列表中的下一個 Entry 的 next Entry
          //創(chuàng)建一個指向上一個列表開頭的新 Entry,
          //并將此新 Entry 插入表中
          Entry e = new Entry(hash, key, value, table[index]);
          table[index] = e;
          return null;
          }
          

           

          如果看一下各種基于哈希的 Map 的源代碼,您將發(fā)現(xiàn)這基本上就是它們的工作原理。 此外,還有一些需要進一步考慮的事項,如處理空鍵和值以及調(diào)整內(nèi)部數(shù)組。 此處定義的 put() 方法還包含相應(yīng) get() 的算法,這是因為插入包括搜索映射索引處的項以查明該鍵是否已經(jīng)存在。 (即 get() 方法與 put() 方法具有相同的算法,但 get() 不包含插入和覆蓋代碼。) 使用鏈接列表并不是解決沖突的唯一方法,某些哈希映射使用另一種“開放式尋址”方案,本文對其不予介紹。

          優(yōu)化 Hasmap

          如果哈希映射的內(nèi)部數(shù)組只包含一個元素,則所有項將映射到此數(shù)組位置,從而構(gòu)成一個較長的鏈接列表。 由于我們的更新和訪問使用了對鏈接列表的線性搜索,而這要比 Map 中的每個數(shù)組索引只包含一個對象的情形要慢得多,因此這樣做的效率很低。 訪問或更新鏈接列表的時間與列表的大小線性相關(guān),而使用哈希函數(shù)訪問或更新數(shù)組中的單個元素則與數(shù)組大小無關(guān) — 就漸進性質(zhì)(Big-O 表示法)而言,前者為 O(n),而后者為 O(1)。 因此,使用一個較大的數(shù)組而不是讓太多的項聚集在太少的數(shù)組位置中是有意義的。

          調(diào)整 Map 實現(xiàn)的大小

          在哈希術(shù)語中,內(nèi)部數(shù)組中的每個位置稱作“存儲桶”(bucket),而可用的存儲桶數(shù)(即內(nèi)部數(shù)組的大小)稱作容量 (capacity)。 為使 Map 對象有效地處理任意數(shù)目的項,Map 實現(xiàn)可以調(diào)整自身的大小。 但調(diào)整大小的開銷很大。 調(diào)整大小需要將所有元素重新插入到新數(shù)組中,這是因為不同的數(shù)組大小意味著對象現(xiàn)在映射到不同的索引值。 先前沖突的鍵可能不再沖突,而先前不沖突的其他鍵現(xiàn)在可能沖突。 這顯然表明,如果將 Map 調(diào)整得足夠大,則可以減少甚至不再需要重新調(diào)整大小,這很有可能顯著提高速度。

          使用 1.4.2 JVM 運行一個簡單的測試,即用大量的項(數(shù)目超過一百萬)填充 HashMap。 表 5 顯示了結(jié)果,并將所有時間標(biāo)準(zhǔn)化為已預(yù)先設(shè)置大小的服務(wù)器模式(關(guān)聯(lián)文件中的 Test3)。 對于已預(yù)先設(shè)置大小的 JVM,客戶端和服務(wù)器模式 JVM 運行時間幾乎相同(在放棄 JIT 編譯階段后)。 但使用 Map 的默認大小將引發(fā)多次調(diào)整大小操作,開銷很大,在服務(wù)器模式下要多用 50% 的時間,而在客戶端模式下幾乎要多用兩倍的時間!

          表 5: 填充已預(yù)先設(shè)置大小的 HashMap 與填充默認大小的 HashMap 所需時間的比較
          客戶端模式 服務(wù)器模式
          預(yù)先設(shè)置的大小 100% 100%
          默認大小 294% 157%

           

          使用負載因子

          為確定何時調(diào)整大小,而不是對每個存儲桶中的鏈接列表的深度進行記數(shù),基于哈希的 Map 使用一個額外參數(shù)并粗略計算存儲桶的密度。 Map 在調(diào)整大小之前,使用名為“負載因子”的參數(shù)指示 Map 將承擔(dān)的“負載”量,即它的負載程度。 負載因子、項數(shù)(Map 大小)與容量之間的關(guān)系簡單明了:

          • 如果(負載因子)x(容量)>(Map 大?。瑒t調(diào)整 Map 大小

           

          例如,如果默認負載因子為 0.75,默認容量為 11,則 11 x 0.75 = 8.25,該值向下取整為 8 個元素。 因此,如果將第 8 個項添加到此 Map,則該 Map 將自身的大小調(diào)整為一個更大的值。 相反,要計算避免調(diào)整大小所需的初始容量,用將要添加的項數(shù)除以負載因子,并向上取整,例如,

          • 對于負載因子為 0.75 的 100 個項,應(yīng)將容量設(shè)置為 100/0.75 = 133.33,并將結(jié)果向上取整為 134(或取整為 135 以使用奇數(shù))

           

          奇數(shù)個存儲桶使 map 能夠通過減少沖突數(shù)來提高執(zhí)行效率。 雖然我所做的測試(關(guān)聯(lián)文件中的Test4)并未表明質(zhì)數(shù)可以始終獲得更好的效率,但理想情形是容量取質(zhì)數(shù)。 1.4 版后的某些 Map(如 HashMap 和 LinkedHashMap,而非 Hashtable 或 IdentityHashMap)使用需要 2 的冪容量的哈希函數(shù),但下一個最高 2 的冪容量由這些 Map 計算,因此您不必親自計算。

          負載因子本身是空間和時間之間的調(diào)整折衷。 較小的負載因子將占用更多的空間,但將降低沖突的可能性,從而將加快訪問和更新的速度。 使用大于 0.75 的負載因子可能是不明智的,而使用大于 1.0 的負載因子肯定是不明知的,這是因為這必定會引發(fā)一次沖突。 使用小于 0.50 的負載因子好處并不大,但只要您有效地調(diào)整 Map 的大小,應(yīng)不會對小負載因子造成性能開銷,而只會造成內(nèi)存開銷。 但較小的負載因子將意味著如果您未預(yù)先調(diào)整 Map 的大小,則導(dǎo)致更頻繁的調(diào)整大小,從而降低性能,因此在調(diào)整負載因子時一定要注意這個問題。

          選擇適當(dāng)?shù)?Map

          應(yīng)使用哪種 Map? 它是否需要同步? 要獲得應(yīng)用程序的最佳性能,這可能是所面臨的兩個最重要的問題。 當(dāng)使用通用 Map 時,調(diào)整 Map 大小和選擇負載因子涵蓋了 Map 調(diào)整選項。

          以下是一個用于獲得最佳 Map 性能的簡單方法

          1. 將您的所有 Map 變量聲明為 Map,而不是任何具體實現(xiàn),即不要聲明為 HashMap 或 Hashtable,或任何其他 Map 類實現(xiàn)。

             

            Map criticalMap = new HashMap(); //好
                HashMap criticalMap = new HashMap(); //差
                

             

            這使您能夠只更改一行代碼即可非常輕松地替換任何特定的 Map 實例。

          2. 下載 Doug Lea 的 util.concurrent 程序包 (http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html)。 將 ConcurrentHashMap 用作默認 Map。 當(dāng)移植到 1.5 版時,將 java.util.concurrent.ConcurrentHashMap 用作您的默認 Map。 不要將 ConcurrentHashMap 包裝在同步的包裝器中,即使它將用于多個線程。 使用默認大小和負載因子。
          3. 監(jiān)測您的應(yīng)用程序。 如果發(fā)現(xiàn)某個 Map 造成瓶頸,則分析造成瓶頸的原因,并部分或全部更改該 Map 的以下內(nèi)容: Map 類;Map 大小;負載因子;關(guān)鍵對象 equals() 方法實現(xiàn)。 專用的 Map 的基本上都需要特殊用途的定制 Map 實現(xiàn),否則通用 Map 將實現(xiàn)您所需的性能目標(biāo)。

           

          Map 選擇

          也許您曾期望更復(fù)雜的考量,而這實際上是否顯得太容易? 好的,讓我們慢慢來。 首先,您應(yīng)使用哪種 Map? 答案很簡單: 不要為您的設(shè)計選擇任何特定的 Map,除非實際的設(shè)計需要指定一個特殊類型的 Map。 設(shè)計時通常不需要選擇具體的 Map 實現(xiàn)。 您可能知道自己需要一個 Map,但不知道使用哪種。 而這恰恰就是使用 Map 接口的意義所在。 直到需要時再選擇 Map 實現(xiàn) — 如果隨處使用“Map”聲明的變量,則更改應(yīng)用程序中任何特殊 Map 的 Map 實現(xiàn)只需要更改一行,這是一種開銷很少的調(diào)整選擇。 是否要使用默認的 Map 實現(xiàn)? 我很快將談到這個問題。

          同步 Map

          同步與否有何差別? (對于同步,您既可以使用同步的 Map,也可以使用 Collections.synchronizedMap() 將未同步的 Map 轉(zhuǎn)換為同步的 Map。 后者使用“同步的包裝器”)這是一個異常復(fù)雜的選擇,完全取決于您如何根據(jù)多線程并發(fā)訪問和更新使用 Map,同時還需要進行維護方面的考慮。 例如,如果您開始時未并發(fā)更新特定 Map,但它后來更改為并發(fā)更新,情況將如何? 在這種情況下,很容易在開始時使用一個未同步的 Map,并在后來向應(yīng)用程序中添加并發(fā)更新線程時忘記將此未同步的 Map 更改為同步的 Map。 這將使您的應(yīng)用程序容易崩潰(一種要確定和跟蹤的最糟糕的錯誤)。 但如果默認為同步,則將因隨之而來的可怕性能而序列化執(zhí)行多線程應(yīng)用程序。 看起來,我們需要某種決策樹來幫助我們正確選擇。

          Doug Lea 是紐約州立大學(xué)奧斯威戈分校計算機科學(xué)系的教授。 他創(chuàng)建了一組公共領(lǐng)域的程序包(統(tǒng)稱 util.concurrent),該程序包包含許多可以簡化高性能并行編程的實用程序類。 這些類中包含兩個 Map,即 ConcurrentReaderHashMap 和 ConcurrentHashMap。 這些 Map 實現(xiàn)是線程安全的,并且不需要對并發(fā)訪問或更新進行同步,同時還適用于大多數(shù)需要 Map 的情況。 它們還遠比同步的 Map(如 Hashtable)或使用同步的包裝器更具伸縮性,并且與 HashMap 相比,它們對性能的破壞很小。 util.concurrent 程序包構(gòu)成了 JSR166 的基礎(chǔ);JSR166 已經(jīng)開發(fā)了一個包含在 Java 1.5 版中的并發(fā)實用程序,而 Java 1.5 版將把這些 Map 包含在一個新的 java.util.concurrent 程序包中。

          后續(xù)步驟

           

          下載 Oracle JDeveloper 10g改變您對 Java 開發(fā)的看法

          Oracle JDeveloper 10g 中的監(jiān)測器該監(jiān)測器利用 Java 虛擬機中的某些特性,使您能夠發(fā)現(xiàn)應(yīng)用程序代碼中的編程缺陷、性能問題以及內(nèi)存泄漏。 可以將監(jiān)測器與調(diào)試器和 CodeCoach 一起使用來進行功能強大且有效的應(yīng)用程序代碼故障排除。 了解更多有關(guān)事件監(jiān)測、執(zhí)行監(jiān)測以及內(nèi)存監(jiān)測的信息。

          所有這一切意味著您不需要一個決策樹來決定是使用同步的 Map 還是使用非同步的 Map, 而只需使用 ConcurrentHashMap。 當(dāng)然,在某些情況下,使用 ConcurrentHashMap 并不合適。 但這些情況很少見,并且應(yīng)具體情況具體處理。 這就是監(jiān)測的用途。

           

          結(jié)束語

          通過 Oracle JDeveloper 可以非常輕松地創(chuàng)建一個用于比較各種 Map 性能的測試類。 更重要的是,集成良好的監(jiān)測器可以在開發(fā)過程中快速、輕松地識別性能瓶頸 - 集成到 IDE 中的監(jiān)測器通常被較頻繁地使用,以便幫助構(gòu)建一個成功的工程。 現(xiàn)在,您已經(jīng)擁有了一個監(jiān)測器并了解了有關(guān)通用 Map 及其性能的基礎(chǔ)知識,可以開始運行您自己的測試,以查明您的應(yīng)用程序是否因 Map 而存在瓶頸以及在何處需要更改所使用的 Map。

          以上內(nèi)容介紹了通用 Map 及其性能的基礎(chǔ)知識。 當(dāng)然,有關(guān)特定 Map 實現(xiàn)以及如何根據(jù)不同的需求使用它們還存在更多復(fù)雜和值得關(guān)注的事項,這些將在本文第 2 部分中介紹。


          Jack Shirazi 是 O'Reilly 的“Java 性能調(diào)整”的作者,以及受歡迎的 JavaPerformanceTuning.com 網(wǎng)站(提供 Java 性能信息的全球知名站點)的總監(jiān)。 Jack 在 Java 性能領(lǐng)域提供咨詢并著書立說。 他還監(jiān)督 JavaPerformanceTuning.com 提供的信息,其中包括每年大約發(fā)布 1000 條性能技巧以及許多有關(guān)性能工具、討論組等內(nèi)容的文章。 Jack 早年還曾發(fā)布有關(guān)蛋白質(zhì)結(jié)構(gòu)預(yù)測以及黑洞熱力學(xué)方面的文章,而且在其空閑時還對某些 Perl5 核心模塊作出了貢獻。

          posted on 2007-07-10 13:58 朱巖 閱讀(206) 評論(0)  編輯  收藏 所屬分類: java文章


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
          相關(guān)文章:
           
          主站蜘蛛池模板: 土默特右旗| 岳阳市| 溆浦县| 呼玛县| 乌海市| 于田县| 鄱阳县| 琼海市| 曲水县| 延安市| 长武县| 尚义县| 龙胜| 台北市| 临泽县| 勐海县| 洪江市| 铅山县| 绍兴县| 红桥区| 洛川县| 汝州市| 金坛市| 简阳市| 招远市| 怀安县| 思南县| 方山县| 桂阳县| 古浪县| 鹰潭市| 昭觉县| 卓资县| 吉水县| 都江堰市| 华坪县| 石渠县| 迭部县| 卓尼县| 新闻| 措勤县|