与Java的LinkedList类并发

时间:2012-06-15 03:36:05

标签: java multithreading concurrency thread-safety

美好的一天,

我在Java中遇到了LinkedList的并发问题。我有一个名为“Connection”的Object类型,它具有名为“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从套接字读取数据。“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()。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

有什么想法吗?非常感谢你的帮助!

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

synchronized块似乎应该有效。我希望在ReadObject synchronized块中调用的方法中存在修改列表的活动。执行MessageHandler的任何呼叫或链接到addNewLoggedInUser(或任何其他可能更新侦听器列表的方法)的调用?

如果是这样,该线程已经让ReadObject synchronized块抓住了该监视器,并且能够在addNewLoggedInUser中输入该块。

答案 2 :(得分: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();
   }
 }