2013-04-08 43 views
3

我已經閱讀了幾條來自不同來源的關於ConcurrentHashmap的聲明,並希望驗證它們是否確實如此。關於Concurrenthashmap的事實

  1. 被創建爲一個ConcurrentHashmap迭代之後,只有通過螺紋移除和更新操作被保證得到反映。 迭代器在編輯/刪除後是否刷新其快照?爲什麼迭代器將一個更新/刪除與ADD不同。

  2. ConcurrentHashmap將其數據分段爲段以減少寫入程序鎖定爭用。 concurrencyLevel參數直接指定內部創建的分片的數量。 如果我們只是使用無參數構造函數,並接受默認配置,那麼在您添加第一個值之前,地圖將實例化16個分片所需的對象... 這裏的分片意味着什麼?它是地圖中的一桶數據 - 還是整個地圖的副本。 我明白這與數據庫中的頁面相似,可以獨立鎖定毛髮更新。 爲什麼concurrencyLevel會影響記憶呢?

+0

'它是如何在內部獲得的?觀看'ConcurrentHashmap'的源代碼。 –

+0

要回答你的第二點:他們是細分市場。每個分段都包含一部分數據。您通過key.hashCode()的散列獲得正確的段。我不會將此作爲答案,因爲我不確定如何回答第一個問題。 – dierre

回答

2

是否迭代器刷新其快照編輯後/刪除爲什麼會 迭代器治療的更新/刪除任何不同於一個ADD?

的CHM的迭代器在API中說明使得

類似地,迭代器和枚舉在一些點返回反射哈希表的 狀態元件在或自創建 迭代器/枚舉。

含義Iterator返回可能反映或不反映迭代時在Map中發生的更改。想象一下,如果您創建迭代器並遍歷整個分段並轉到下一個分段。在進入下一個段之後,您完成遍歷的第一個段添加或刪除完成。那麼你不會看到,沒關係,它沒有違反API。

至於你的第二個問題。隱含添加,添加和刪除之間的可見性沒有區別。

爲什麼concurrencylevel會影響內存呢?

自發布以來,內存一直是ConcurrentHashMap的問題。默認情況下,每個併發級別都會創建一個Segment。這個段有一個HashEntry表,也是一個Reentrant鎖(因此也是所有必需品)。

Java 8 is released CHMv8這實際上解決了這個問題。

你可以閱讀更多的內存here,具體是:

雖然做存儲的個人資料,JVisualVM表明頂部罪魁禍首 是ConcurrentHashMap.Segment類。每個ConcurrentHashMap的默認編號 段爲16. 段中的HashEntry表可能很小,但每個段都是一個ReentrantLock。 每個ReentrantLock包含一個Sync,在這種情況下是一個NonFairSync,其中 是Sync的一個子類,然後是AbstractQueuedSynchronizer。其中的每個 都包含一個節點隊列,用於維護線程發生的 狀態。在確定公平性時使用它。 此隊列和節點使用大量內存。

+1

只是爲了澄清第一個問題 - 是否意味着對於迭代器,更新/刪除與添加沒有區別呢?迭代器是否能夠查看更新/刪除/添加將取決於操作是否發生在'積極'的細分市場上。'積極',我的意思是目前正在穿越的細分市場? – IUnknown

+0

@IUnknown是的,這是完全正確的! –

0

請記住,哈希表只是一個數組,它的核心是一些聰明的東西,允許您使用非整數鍵並且仍然可以獲得常量時間訪問。

  1. 對於添加,添加元素可能會導致哈希表增長,從而創建新的基礎數組並重新排序表中的元素。哈希的迭代器將大概指向舊的數組,以便它可以保持其位置。

  2. 通常情況下,在這種情況下分片意味着地圖被分割成一些數量的子陣列,所以你不可能每次都擊中多個地圖。對於大多數情況來說,如果指定的碎片數量較少,實際上會更好,除非您在該表上存在大量爭用的服務器上運行,否則通常就足夠了。另請參見:

http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/

1
  1. 如果你指的是枚舉的entrySet,這將(最終)反映了添加和刪除父對象上執行的操作。但是,枚舉本身不支持添加操作。

  2. 這種情況下的分片本質上是散列表的散列表。假設ConcurrentHashMap的backing數組包含1024個條目。如果不分片,這意味着對象的哈希值將映射到[0,1023]之間的整數。這意味着支持數組包含64個條目的16個支持數組,即[0,1023]支持數組現在是來自[0,63]的數組,來自[64,127]等的另一個數組。 '修改一個散列爲100的對象 - 而不分割你會鎖定整個[0,1023]支持數組,但是使用分片你只能鎖定[64,127]子數組,允許額外的線程修改其他碎片。分片越多,ConcurrentHashMap的併發性就越大,但是更多的分片需要更多的內存來維護它們。 (然而,這不是乘法效應,使用16個碎片將使用的內存總量乘以16。相反,這是一個疊加效應;假設需要64個字節來維護每個碎片的數據結構,因此使用16個碎片將1024字節添加到數據結構中,並且使用64個碎片將4096字節添加到數據結構。)