与Java的并发性';s LinkedList类

与Java的并发性';s LinkedList类,java,multithreading,concurrency,thread-safety,Java,Multithreading,Concurrency,Thread Safety,你好 我与Java中的LinkedList存在并发问题。我有一个名为“Connection”的对象类型,它的成员变量是名为“listeners”的“MessageHandlers”的LinkedList。然后我有两个不同的线程,一个在修改,另一个在同一个LinkedList上迭代 我见过许多其他的StackOverflow问题,建议使用同步化的代码块,但这似乎并没有帮助所有人。我还尝试将LinkedList创建为一个并发的链接列表,但我仍然收到 Exception in thread "Thr

你好

我与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;
}
然后调用方法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;
}
公共连接()
{
//将变量初始化为NULL
socket=null;
输出=空;
输入=空;
receiveThread=null;
runReceiveThread=false;
listeners=Collections.synchronizedList(新的LinkedList());
//处理ID计数器。现在,每个连接都有一个唯一的ID
connectionID=计数器ID;
计数器ID=计数器ID+1;
}
这是连接类的构造函数。注意他收藏。同步列表


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

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


如果是这样的话,线程将已经让监视器被
ReadObject
同步
块抓取,并且能够在
addNewLoggedInUser
java.util.ConcurrentModificationException
中输入该块。这是由于修改了由迭代器锁定的列表造成的。我想您是从
MessageReceived()
调用
addNewLoggedInUser()
。这将导致并发修改异常,因为调用函数在linkedlist上已经有迭代器锁。

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

同步块参数中的user.getConnection().getListeners()和listeners是否为同一实例?在对列表进行迭代时更改列表(添加/删除元素)时引发。您可以使用单个线程导致此异常。除非有多个线程同时访问列表,否则不需要任何类型的并发集合。例如。@George谢谢!我很长时间都不明白你的意思,因为我认为我没有很好地解释代码,因为我认为你的回答太离谱了。事实证明,你是完全正确的!我没有看到我在做什么,直到我在一个较小的示例上再次这样做,并看到相同的异常被抛出。谢谢你的帮助,乔治!是的,我的一个MessageHandler调用addNewLoggedInUser。我不熟悉“监视器”是什么,所以我必须对此做一些研究。谢谢你的提示。
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();
   }
 }