2012-05-21 158 views
0

我正在用java創建一個多線程聊天。當用戶u1向用戶u2發送消息但用戶u2未連接時,用戶u1將該消息發送給服務器,並且用戶u2在他連接到服務器後將接收該消息。未發送的消息將被添加到ArrayList。一旦用戶連接,他會檢查他是否是未決消息的收件人。如果他是,則將消息發送給他,然後從待處理消息列表中刪除。這就是我要做的事:數組併發修改

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) { 
    String pendingmsg = itpendingmsgs.next(); 
    String dest = pendingmsg.substring(4);    
    if (protocol.author.equals(dest)) { 
     sendMsg(msg); 
     pendingmsgs.remove(pendingmsg); 
    } 
} 

這就是我得到:

Exception in thread "Thread-3" java.util.ConcurrentModificationException 
at java.util.AbstractList$Itr.checkForComodification(Unknown Source) 
at java.util.AbstractList$Itr.next(Unknown Source) 
at ChatServer$ClientConnection.run(ChatServer.java:383) 
at java.lang.Thread.run(Unknown Source) 

如何解決呢?是因爲我在使用迭代器嗎?

+0

不能使用刪除,而迭代 – keyser

回答

3

代替此

pendingmsgs.remove(pendingmsg); 

使用

itpendingmsgs.remove(); 

ArrayListIteratorfail fast,因此,儘管要使用的Iterator遍歷ArrayList如果底層ArrayList被其他任何方法改性比addremove由提供10本身它會拋出ConcurrentModificationException並且將被保釋出來。

在你當前的實現,而你是通過在一定條件下,你也可以通過調用底層ArrayListremove修改清單列表循環,而不是調用Iteratorremove方法。

從Java文檔:此類的迭代器返回和的ListIterator

的迭代器 方法是快速失敗的:如果列表在任何 時間結構上修改迭代器創建之後,以任何方式除了通過 迭代器自己的remove或add方法,迭代器將拋出 ConcurrentModificationException。因此,面對併發的修改,迭代器很快並且乾淨地失敗,而不是冒着在將來確定的時間 處的任意的,不確定的行爲冒險。

注意,迭代器的快速失敗行爲不能得到保證 ,因爲它是,一般來說,不可能作出任何硬性保證 不同步併發修改的存在。迭代器在盡力而爲 的基礎上拋出ConcurrentModificationException時出現快速失敗 。因此,編寫一個依賴於此例外的 的程序是錯誤的,因爲它的正確性: 迭代器的故障快速行爲應僅用於檢測錯誤。

1

除了通過iterator實例本身,您不得在遍歷整個列表時修改列表。您必須致電itpendingmsgs.remove()

1

而不是

pendingmsgs.remove(pendingmsg); 

使用

itpendingmsgs.remove(); 

參見:

如果底層 集合被修改,迭代過程中的迭代器的行爲是不確定的除了通過調用此方法以外的任何方式 。

來源:Java API

1

基於文檔ArrayList api此類的iterator和listIterator方法返回的迭代器是快速失敗的:如果列表在任何時間從結構上修改創建迭代器之後,在任何除了通過迭代器自己的remove或add方法外,迭代器將拋出ConcurrentModificationException。

當您迭代它時,您不應該從集合中移除它。您應該使用迭代器的remove方法。

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) { 
String pendingmsg = itpendingmsgs.next(); 
String dest = pendingmsg.substring(4);    
if (protocol.author.equals(dest)) { 
    sendMsg(msg); 
    itpendingmsgs.remove(); 
} 

}