简体   繁体   English

与Java的LinkedList类并发

[英]Concurrency with Java's LinkedList class

Good Day, 美好的一天,

I am having concurrency problems with a LinkedList in Java. 我在Java中使用LinkedList存在并发问题。 I have an Object type called "Connection" which has as a member variable LinkedList of "MessageHandlers" called "listeners". 我有一个名为“Connection”的Object类型,它具有名为“listeners”的“MessageHandlers”的成员变量LinkedList。 I then have two different threads, one modifying and one iterating over the same LinkedList. 然后我有两个不同的线程,一个修改,一个迭代在同一个LinkedList上。

I've seen many many other StackOverflow questions that suggest to use the sychronized block of code, but that doesn't appear to be helping it all. 我已经看到许多其他StackOverflow问题建议使用同步的代码块,但这似乎并没有帮助它。 I've also try creating the LinkedList as a concurrent linked list, but I am still receiving the 我也尝试将LinkedList创建为并发链表,但我仍然收到了

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

exception. 例外。 Does anyone have any other suggestions to try? 有没有人有任何其他建议尝试? Here are some snipbits of my code... 以下是我的代码的一些代码段...

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;
}

The above code is inside my connection object. 上面的代码在我的连接对象中。 It gets called from a function that has a socket's ObjectInputStream reading data from the socket."input" is an instance of ObjectInputStream. 它从一个具有套接字的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();
}

I then call the method user.getConnection().getListeners().add(this) and thus am getting the exception. 然后我调用方法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;
}

This is the constructor for the connection class. 这是连接类的构造函数。 Notice he Collections.synchronizedList 注意他是Collections.synchronizedList

Any ideas? 有任何想法吗? Thank you very much for your help! 非常感谢您的帮助!

java.util.ConcurrentModificationException isn't really a threading issue. java.util.ConcurrentModificationException实际上不是一个线程问题。 It is cause by modification of a list locked by it's iterator. 它是由修改由它的迭代器锁定的列表引起的。 I think you are calling addNewLoggedInUser() from MessageReceived() . 我想你是从MessageReceived()调用addNewLoggedInUser() MessageReceived() This would cause the concurrent modification exception since the calling function already has iterator lock on the linkedlist. 这会导致并发修改异常,因为调用函数已经在链表上有迭代器锁。

The synchronized blocks look like they should work. synchronized块看起来应该可以工作。 I would expect that there is activity in methods called from within the ReadObject synchronized block which modify the list. 我希望在ReadObject synchronized块中调用的方法中有活动来修改列表。 Do any of your MessageHandler s call or chain to a call to addNewLoggedInUser (or any other method that might update the listener list)? 您是否对MessageHandler的任何调用或链调用addNewLoggedInUser (或可能更新侦听器列表的任何其他方法)?

If so, the thread would already have the monitor grabbed by the ReadObject synchronized block, and would be able to enter the block in addNewLoggedInUser . 如果是这样,该线程已经有ReadObject synchronized块抓取的监视器,并且能够在addNewLoggedInUser输入该块。

Go through BlockingQueue javadoc. 通过BlockingQueue javadoc。 It mentions a simple scenario as well that fits your requirements ie 它提到了一个符合您要求的简单场景,即

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();
   }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM