[英]Avoiding ConcurrentModificationException in Event Bus
I have a EventBus
system which clients can at will join / leave. 我有一个
EventBus
系统,客户可以随意加入/离开。
The EventBus
is using HashSet
to keep track of clients, and when a message is broadcasted, it's delivered to all registered clients. EventBus
使用HashSet
来跟踪客户端,并在广播消息时将其传递给所有注册的客户端。
// clients - HashSet of clients.
// message - event object to be delivered
for (Object client : clients) {
sendTo(client, message);
}
I know this is inefficient, but I don't know how to improve it. 我知道这是低效的,但我不知道如何改善它。
The problem is that the clients can react to some events by disconnecting from the bus. 问题在于客户端可以通过断开与总线的连接来对某些事件做出反应。 Let's take it as a fact, it must be possible.
让我们将其视为事实,这一定是可能的。
They call this method: 他们称这种方法:
public void unsubscribe(Object client)
{
clients.remove(client);
}
And then, of course, I get an error: 然后,当然,我得到一个错误:
[!E!] java.util.ConcurrentModificationException
[!E!] at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
[!E!] at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:401)
[!E!] at mightypork.utils.control.bus.EventChannel.doBroadcast(EventChannel.java:56)
[!E!] at mightypork.utils.control.bus.EventChannel.broadcast(EventChannel.java:48)
[!E!] at mightypork.utils.control.bus.EventBus.broadcast(EventBus.java:82)
[!E!] at mightypork.rogue.App.shutdown(App.java:133)
[!E!] at mightypork.rogue.App.start(App.java:87)
[!E!] at mightypork.rogue.App.main(App.java:72)
[!E!]
Not cool, right? 不酷吧?
Any idea to fix this? 有解决这个问题的主意吗?
You can use a LinkedList for this. 您可以为此使用LinkedList 。
With a LinkedList, you can use its iterator to loop through it, and use that same iterator to remove the object from the LinkedList. 使用LinkedList,您可以使用其迭代器在其中循环,并使用相同的迭代器从LinkedList中删除对象。
Example: 例:
List<Client> clients = new LinkedList<>();
Iterator it = clients.iterator();
while (it.hasNext())
{
Client client = (Client) it.next();
sendTo(client, message);
it.remove();
}
The easiest way is mark clients which should be removed and then remove them in "safe" place. 最简单的方法是标记应删除的客户端,然后在“安全”位置将其删除。
public void unsubscribe(Object client)
{
clientsToRemove.add(client);
}
And in code something like this : 并在代码中是这样的:
for (Object client : clients) {
sendTo(client, message);
}
client.removeAll(clientsToRemove);
If you use an Iterator, you can modify a collection during iteration. 如果使用Iterator,则可以在迭代期间修改集合。 For more information, see The Collection Interface tutorial: http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html
有关更多信息,请参见“收集接口”教程: http : //docs.oracle.com/javase/tutorial/collections/interfaces/collection.html
I've solved it by using CopyOnWriteArraySet
instead of HashSet
. 我已经通过使用
CopyOnWriteArraySet
而不是HashSet
解决了它。
Thanks for the suggestions anyway, it can help someone else. 无论如何,感谢您的建议,它可以帮助其他人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.