2011-02-28 49 views
4

我有一個Server類和一個Timer,它應該可以清除死客戶端(崩潰的客戶端)。我在下面的例子中通過在Timer迭代用戶時鎖定集合,但我仍然得到這個異常(在我崩潰連接的客戶端之後)。ArrayList上的java.util.ConcurrentModificationException

http://www.javaperformancetuning.com/articles/fastfail2.shtml

List<User> users; 
List<User> connectedUsers; 
ConcurrentMap<User, IClient> clients; 

... 

users = Collections.synchronizedList(new ArrayList<User>()); 
connectedUsers = new ArrayList<User>(); 
clients = new ConcurrentHashMap<User, IClient>(); 
timer = new Timer(); 
timer.schedule(new ClearDeadClients(), 5000, 5000); 

... 

class ClearDeadClients extends TimerTask { 
    public void run() { 
     synchronized (users) { 
      Iterator<User> it = users.iterator(); 
      while (it.hasNext()) { 
       User user = it.next(); // Throws exception 
       if (!connectedUsers.contains(user)) { 
        users.remove(user); 
        clients.remove(user); 
       } 
      } 
     }  

     connectedUsers.clear(); 
    } 
} 
+1

可能的重複[list on remove loop](http:// stackoverflow。com/questions/1921104/loop-on-list-with-remove) – 2011-02-28 17:29:51

回答

9

在遍歷它不能修改的集合 - 不幸的是你做的,這裏與users,而ConcurrentModificationException的是結果。從ArrayList中自己javadocs

此類的iteratorlistIterator方法返回的迭代器是快速失敗的:如果列表在任何時間通過迭代器的結構修飾在創建迭代器之後,以任何方式,除了自己的removeadd方法,迭代器將拋出ConcurrentModificationException。因此,面對併發修改,迭代器快速而乾淨地失敗,而不是在將來某個未確定的時間冒着任意的,非確定性的行爲風險。

要解決這種特定情況下,你也可以使用迭代器自身的remove()方法,通過更換這行:

it.remove(); 

後者的操作

users.remove(user); 

從集合中刪除迭代器返回的最後一個元素。 (這個用法避免了異常,因爲迭代器知道的變化,並且能夠確保它是安全的;通過外部修改,迭代器無法知道其遍歷的狀態是否仍然一致,因此快速失敗)。

在某些情況下,這種立即拆除可能不是可行的,在這種情況下,有三種可供選擇的一般方法:

  1. 採取集合(users在這種情況下)的副本,遍歷副本並刪除原件中的元素。
  2. 在迭代過程中,構建一組要刪除的元素,然後在迭代完成後執行批量刪除。
  3. 使用的List實現可處理併發修改,像CopyOnWriteArrayList

這是一個相當普遍的問題 - 也見(例如)其他答案loop on list with remove問題。

+3

添加到列表中:3.使用'List'實現可以處理併發修改,如'CopyOnWriteArrayList'。 – Waldheinz 2011-02-28 17:23:53

+0

謝謝@Waldheinz--合併。 – 2011-02-28 17:29:27

11

您需要從迭代器中刪除集合。它會看起來像這樣:

Iterator<User> it = users.iterator(); 
while (it.hasNext()) { 
    User user = it.next(); 
    if (!connectedUsers.contains(user)) { 
     it.remove(); 
     clients.remove(user); 
    } 
} 
+0

感謝它工作:) – Lightforce 2011-02-28 20:19:44

相關問題