2011-08-11 35 views
1

從ConcurrentWeakKeyHashMap.java以下是的isEmpty()方法, https://github.com/netty/netty/blob/master/src/main/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMap.javaConcurrentWeakKeyHashMap的isEmpty方法

爲什麼它需要mcsum,又是什麼的,如果(mcsum!= 0){..}塊在做什麼?

更重要的是,我怎麼

if (segments[i].count != 0 || mc[i] != segments[i].modCount) 

評估爲真?

public boolean isEmpty() { 
    final Segment<K, V>[] segments = this.segments; 
    /* 
    * We keep track of per-segment modCounts to avoid ABA problems in which 
    * an element in one segment was added and in another removed during 
    * traversal, in which case the table was never actually empty at any 
    * point. Note the similar use of modCounts in the size() and 
    * containsValue() methods, which are the only other methods also 
    * susceptible to ABA problems. 
    */ 
    int[] mc = new int[segments.length]; 
    int mcsum = 0; 
    for (int i = 0; i < segments.length; ++ i) { 
     if (segments[i].count != 0) { 
      return false; 
     } else { 
      mcsum += mc[i] = segments[i].modCount; 
     } 
    } 


    // If mcsum happens to be zero, then we know we got a snapshot before 
    // any modifications at all were made. This is probably common enough 
    // to bother tracking. 
    if (mcsum != 0) { 
     for (int i = 0; i < segments.length; ++ i) { 
      if (segments[i].count != 0 || mc[i] != segments[i].modCount) { 
       return false; 
      } 
     } 
    } 


    return true; 
} 

編輯: 代碼以評價以上如果塊現在處於ConcurrentWeakKeyHashMapTest

本質1個螺紋汽車無監視concurrentMap,而另一個線程連續添加/刪除相同密鑰對值

回答

1

這種方法是在相同的版本ConcurrentHashMap副本。

這種Map使用modCount每段在操作過程中跟蹤,如果它由不同的踏面保持不變。在遍歷Map的過程中,實際上可能會有其他操作修改Map。這被稱爲ABA problem。我們詢問地圖是否爲空,事實上並非如此,但意外情況似乎如此。一個簡單的例子:

Map with three segements 
Segment 1: size=0 
Segment 2: size=0 
Segment 3: size=1 
  1. 在這個時刻,我們決定要求地圖,並考慮部分1,這似乎是空的。

  2. 現在另一種算法來了,並將一個元素插入段1,但從段3中刪除另一個元素。該映射從不爲空。

  3. 我們的線程現在再次運行,並且我們查看段2和3,它們都是空的。對我們來說,地圖是空的 - 因此。

但是對於任何空槽,我們都會跟蹤它是否被修改過。對於插槽3,我們意識到已經進行了修改:mc[2]>=1這意味着mcsum>=1。這意味着:自從構建Map以來,至少修改了一次。所以要回答mcsum的用途:它是默認的空ConcurrentHashMap的快捷方式。如果沒有修改,我們不需要檢查併發修改。

因此我們知道發生了一些事情並再次檢查每個段。如果現在細分市場是空的,我們知道它的modCount已經。對於段3,假設它是1,對於段1,它是0.檢查段1的modCount現在它是1,並且count> 0,所以我們知道該映射不是空的。

在第二個循環中仍然可能存在ABA問題。但是因爲我們知道modCounts,所以我們可以捕獲任何其他併發算法來改變某些東西。所以我們說如果這個段是空的,並且modCount有一些變化,它首先不是空的。也就是說,第二個循環在做什麼。

希望這會有所幫助。

編輯

更重要的是,我怎麼

if (segments[i].count != 0 || mc[i] != segments[i].modCount) 

評估爲真?

如果某個段包含某些內容或自第一個循環以來某些內容已被修改,則其計算結果爲true。如果段不包含任何內容,則它的計算結果爲false(意思是:段爲空),自第一次循環以來沒有任何變化。或者,換一種說法:我們可以確定,自從首先查看受檢節段後,它一直是空的。

+0

感謝您的詳細解答。現在我只需要提供一個java代碼來測試上面的內容,試圖將上面的if塊評估爲true – portoalet

+0

對於這個塊來說,它實際上很簡單:只需將一個元素插入到正在檢查的段中即可。 –

+0

要測試的代碼位於:https://github.com/lydonchandra/netty/blob/master/src/test/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMapTest.java – portoalet

1

mcsum檢查地圖是否經過結構修改。似乎沒有辦法將修改計數重置爲零,因此如果地圖曾經包含任何內容,則mcsum將不爲零。

只有當地圖通過put,remove等等被改變時,弱鍵纔會被清理,而且它們只在修改後的段中被清除。從地圖中檢索值不會清除弱鍵。這意味着所實現的地圖將包含許多已經被垃圾收集的弱密鑰,因爲如果修改了相同的網段,它們只會被清理乾淨。

這意味着來自size()isEmpty()方法的結果經常會返回錯誤的結果。

使用API​​提供的最佳方法是在檢查地圖是否爲空之前先致電purgeStaleEntries()