2013-07-21 18 views
1

我想實現一個函數,對ConcurrentHashMap的元素執行循環法。例如,如果ConcurrentHashMap中有{a,b,c}元素,那麼當我第一次調用該函數時,它將返回a,第二次,返回b,第三次,返回c,第四次,它返回一個。ConcurrentHashMap上的元素循環法

private static Enumeration<Peer> nhEnmu; 
private static final ConcurrentHashMap<String, Peer> peers; 

private synchronized static Peer getNextPeer() 
{ 
    if (nhEnmu == null || !nhEnmu.hasMoreElements()) 
    { 
     nhEnmu = peers.elements(); 
    } 

    return nhEnmu.nextElement(); 
} 

我實現如上這個功能,但是,NoSuchElementException異常不斷坡平了,我想知道這是有什麼毛病,使用元素()方法?如果不合適,我應該調整哪些實施?謝謝!

的異常跟蹤如下:

at Main$MsgProcessorThread.run(Main.java:119) 
Exception in thread "Thread-1" java.util.NoSuchElementException at 
java.util.concurrent.ConcurrentHashMap$HashIterator.nextEntry(ConcurrentHashMap.java:1266) at 
java.util.concurrent.ConcurrentHashMap$ValueIterator.nextElement(ConcurrentHashMap.java:1297) at 
control.Protocol.getNextPeer(Protocol.java:89) 
+0

我們可以看到異常報告嗎? – tbodt

+0

當然@tbodt,我在帖子中包含了這個報告 –

+1

剛纔意識到,如果你的hashmap是空的,就會發生這個異常。僅僅因爲你枚舉並不意味着它有一個項目。 –

回答

1

根據返回的不是線程安全this question迭代器。如果是這樣,並且您正在多線程上訪問迭代器,則可能會發生此異常。

您可能有一種方法來添加和刪除此類中的同位體。嘗試保留列表中的同伴和索引。當你刪除一個對等體時,從hashmap和你的對等循環體列表中刪除該對等體,並適當地更新你的索引。添加時做同樣的事情。

然後當調用getNextPeer時,返回列表中的下一個對象並增加索引。如果索引超出列表的大小,則回到零。

喜歡的東西....

private static List<Peer> nhEnmu; 
private static int index; 
private static final ConcurrentHashMap<String, Peer> peers; 

private synchronized static Peer getNextPeer() 
{ 
    Peer peer = null; 
    if (nhEnmu.size()>0) 
    { 
     peer = nhEnmu.get(index); 
     index++; 
     if(index>=nhEnmu.size()) 
      index = 0; 
    } 
    return peer; 
} 
+0

我試着在函數和nhEnmu迭代器上使用synchronized關鍵字,但是,這個異常仍然存在。我想知道該怎麼做才能使這個函數線程安全? –

+0

我會放棄枚舉並採取我在編輯中建議的方法。或者,查看'ConcurrentHashMap'的源代碼,看看枚舉正在做什麼。我只是看着源頭,它的複雜。 –

0

使用ConcurrentHashMap.entrySet(),而不是直接。它是安全的。

+0

在我的答案中鏈接的問題與此相矛盾。 –

+0

我不這麼認爲,它說:「總之,像(對象o:someConcurrentHashMap.entrySet()){ // ... } } 幾乎每次都可以(或至少是安全的)你看到它。「如果你總是鏈接到entrySet(),它是安全的,但它可能在迭代期間改變,並可能拋出異常。 – Milad

+0

幾乎是這裏的關鍵詞。如果多個線程在結構上運行,它不是一個安全的。 –