2012-06-15 40 views
0

美好的一天,併發Java的LinkedList類

我有一個Java中的LinkedList的併發問題。我有一個稱爲「連接」的對象類型,它具有名爲「偵聽器」的「MessageHandlers」的成員變量LinkedList。然後我有兩個不同的線程,一個修改和一個遍歷同一個LinkedList。

我見過很多其他的StackOverflow問題,建議使用sychronized代碼塊,但這似乎並沒有幫助所有。我也嘗試創建LinkedList作爲併發鏈表,但我仍然收到

Exception in thread "Thread-1" java.util.ConcurrentModificationException 

異常。有沒有人有任何其他建議嘗試?這裏是我的代碼snipbits ...

public synchronized Object ReadObject() throws java.io.IOException 
{ 
    Object obj = null; 

    try 
    { 
     obj = input.readObject(); 

     synchronized(listeners) 
     { 
      Iterator<MessageHandler> i = listeners.iterator(); 

      while(i.hasNext()) 
      { 
       i.next().MessageReceived(obj, this); 
      } 
     } 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
     throw e; 
    } 
    catch (ClassNotFoundException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    return obj; 
} 

上述代碼是在我的連接對象。它從一個函數調用,該函數有一個套接字的ObjectInputStream從套接字讀取數據。「input」是ObjectInputStream的一個實例。

public void addNewLoggedInUser(User user) throws Exception 
{ 
    for(User u:loggedInUsers) 
    { 
     if(u == user) 
     { 
      throw new Exception("That user is already logged in"); 
     } 
    } 

    //Add the new users 
    loggedInUsers.add(user); 

    synchronized(user.getConnection().getListeners()) 
    { 
     user.getConnection().getListeners().add(this); 
    } 

    this.SendGameStatusUpdateToAllLoggedinPlayers(); 
} 

我然後調用該方法user.getConnection()。getListeners()。添加(本),因此我得到的例外。

public Connection() 
{ 
    //Initialize the variables to NULL 
    socket    = null; 
    output    = null; 
    input    = null; 
    receiveThread  = null; 
    runReceiveThread = false; 
    listeners   = Collections.synchronizedList(new LinkedList<MessageHandler>()); 

    //Handle the ID counter. Now we have a unique ID for every connection that comes in 
    connectionID = counterID; 
    counterID = counterID + 1; 
} 

這是連接類的構造函數。注意他Collections.synchronizedList

任何想法?非常感謝您的幫助!

+0

是否在同步塊參數中存在user.getConnection()。getListeners()和listeners實例? – George

+0

['ConcurrentModificationException'](http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html)在迭代時更改列表(添加/刪除的元素)時引發超過它。您可以使用單個線程導致此異常。除非有多個線程同時訪問列表,否則不應該需要任何類型的併發收集。 –

+0

http://ideone.com/pUPCn爲例。 –

回答

0

​​塊看起來應該可以工作。我期望在修改列表的ReadObject​​塊內調用方法中有活動。請撥打您的MessageHandler的電話或鏈接到addNewLoggedInUser(或其他任何可能更新收聽者列表的方法)的電話?

如果是這樣,線程將已經擁有由ReadObject​​塊抓住的顯示器,並且能夠在addNewLoggedInUser中輸入該塊。

+0

是的,我的一個MessageHandler的調用addNewLoggedInUser。我不熟悉「監視器」是什麼,所以我將不得不對此做一些研究。謝謝你的提示。 – Matthew

2

java.util.ConcurrentModificationException不是一個真正的線程問題。這是由修改迭代器鎖定的列表引起的。我想你是從MessageReceived()呼叫addNewLoggedInUser()。這會導致併發修改異常,因爲調用函數已經在鏈表上存在迭代器鎖定。

0

通過BlockingQueue javadoc。它提到了一個簡單的場景以及適合您的要求,即

class Producer implements Runnable { 
    private final BlockingQueue queue; 
    Producer(BlockingQueue q) { queue = q; } 
    public void run() { 
    try { 
     while (true) { queue.put(produce()); } 
    } catch (InterruptedException ex) { ... handle ...} 
    } 
    Object produce() { ... } 
} 

class Consumer implements Runnable { 
    private final BlockingQueue queue; 
    Consumer(BlockingQueue q) { queue = q; } 
    public void run() { 
    try { 
     while (true) { consume(queue.take()); } 
    } catch (InterruptedException ex) { ... handle ...} 
    } 
    void consume(Object x) { ... } 
} 

class Setup { 
    void main() { 
    BlockingQueue q = new SomeQueueImplementation(); 
    Producer p = new Producer(q); 
    Consumer c1 = new Consumer(q); 
    Consumer c2 = new Consumer(q); 
    new Thread(p).start(); 
    new Thread(c1).start(); 
    new Thread(c2).start(); 
    } 
}