我有一个第二个线程用于使用OSC发送消息。 从主线程我添加消息,我遇到了ConcurrentModificationException的问题。
我做了什么来修复它是我创建了一个新列表,其中包含要添加的消息。 在第二个线程中,我将这些消息添加到我要发送的列表中。
目前它没有任何问题,但我想知道那是运气吗? 换句话说,可能是遇到ConcurrentModificationException的更改仍然存在,但现在真的很小,还是我真的解决了这个问题?
public void run() {
while (running) {
toSend.addAll(newMessages);
newMessages.clear();
Iterator<OSCPriorityMessage> itr = toSend.iterator();
while (itr.hasNext()) {
OSCPriorityMessage msg = itr.next();
oscP5.send(msg, netAddress);
itr.remove();
}
try {
sleep((long)(waitTime));
}
catch (Exception e) {
}
}
}
在这里我添加要发送的消息:
public void send(OSCPriorityMessage msg) {
newMessages.add(msg);
}
答案 0 :(得分:1)
您仍然需要在访问newMessages
时进行同步。我们在这里看到的两个地方是1)添加到它和2)将其复制到toSend
然后清除它。也许还有更多。
public void send(OSCPriorityMessage msg) {
synchronized(newMessages){
newMessages.add(msg);
}
}
要明确toSend
是一个临时的本地列表,仅用于发送过程,请将其声明为本地变量。
而不是
toSend.addAll(newMessages);
newMessages.clear();
你可以做到
ArrayList<OSCPriorityMessage> toSend;
synchronized(newMessages){
toSend = new ArrayList<>(newMessages);
newMessages.clear();
}
如果没有这种同步,你可能会错过一些消息(或者让它们两次,或者可能是一些非常奇怪的东西),因为它们会被同时添加。
现在你在每次循环迭代中都有一个新的toSend
,你实际上不再需要删除这些元素,并且可以取消整个迭代器,用一个简单的循环替换它:
for (OSCPriorityMessage msg: toSend){
oscP5.send(msg, netAddress);
}
最后,正如@dlev建议的那样,看一下java.util.concurrent
包中现有的线程安全队列实现。