美好的一天,
我在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
有什么想法吗?非常感谢你的帮助!
答案 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();
}
}