0

再会,

我在 Java 中遇到了 LinkedList 的并发问题。我有一个名为“Connection”的对象类型,它有一个名为“listeners”的“MessageHandlers”的成员变量 LinkedList。然后我有两个不同的线程,一个修改和一个迭代同一个 LinkedList。

我已经看到许多其他 StackOverflow 问题建议使用同步代码块,但这似乎并没有帮助全部。我也尝试将 LinkedList 创建为并发链表,但我仍然收到

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

例外。有没有人有任何其他建议可以尝试?这是我的代码的一些片段......

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 从套接字读取数据。“输入”是 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().add(this)并因此得到异常。

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

有任何想法吗?非常感谢您的帮助!

4

3 回答 3

2

java.util.ConcurrentModificationException不是真正的线程问题。这是由于修改了被它的迭代器锁定的列表。我想你是addNewLoggedInUser()MessageReceived(). 这将导致并发修改异常,因为调用函数已经在链表上具有迭代器锁。

于 2012-06-15T03:48:57.210 回答
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();
   }
 }
于 2012-06-15T05:57:36.513 回答
0

这些synchronized块看起来应该可以工作。我希望从ReadObject synchronized修改列表的块中调用的方法中有活动。您是否有任何MessageHandler调用或链接到调用addNewLoggedInUser(或任何其他可能更新侦听器列表的方法)?

如果是这样,线程将已经被ReadObject synchronized块抓住了监视器,并且能够在addNewLoggedInUser.

于 2012-06-15T03:47:30.267 回答