[
https://issues.apache.org/jira/browse/WICKET-5619?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14185265#comment-14185265
]
Daniel Kernebeck commented on WICKET-5619:
------------------------------------------
This issue still occurs in our webapplication.
The exception is easy reproducable on the following way:
You have multiple users surfing a page (Page A) which has subscribes for an
event (Event A). Now a user (User A) does an action which triggers the Event A
to get posted to the Eventbus. While the eventbus posts the event to the
registered listeners, a User B leaves the page and unregisters for the event,
f.e because he now want's surfs another page, which does not subscribe to the
event. Now the ConcurrentModificationException occurs because the unregistering
of User B changed the list of listeners while the eventbus is still posting the
event to the different listeners. This happen because the unregistin
In my opinion this issue can be solved if the line:
{code} Collection<EventSubscription> eventSubscriptions =
subscriptions.get(key);
subscriptionsForPage = Iterables.filter(eventSubscriptions, new
EventFilter(event)); {code}
makes an copy of the EventSubscriptions an works on this copy instead on the
original list. When the eventbus now trys to post the event on a component
which does not exists anymore he could try to unregister the component from the
original subscribers list.
Also:
{code}
Iterable<EventSubscription> subscriptionsForPage;
synchronized (this)
{
key = trackedPages.get(resource.uuid());
Collection<EventSubscription> eventSubscriptions =
subscriptions.get(key);
subscriptionsForPage =
Iterables.filter(eventSubscriptions, new EventFilter(event));
}
{code}
creates a lazy iterator on the the {{eventSubscriptions}}, and will be iterated
outside the synchronized block.
You need to create a copy of the eventSubscriptions, because this might be
changed during the unregistering process:
{code}
public synchronized void unregister(Component component)
{
...
Collection<EventSubscription> subscriptionsForPage =
subscriptions.get(pageKey);
Iterator<EventSubscription> it =
subscriptionsForPage.iterator();
while (it.hasNext())
{
if (it.next().getComponentPath().equals(componentPath))
it.remove();
}
}
{code}
{{it.remove()}} changes the iterator within the lazy Iterator!
> ConcurrentModificationException may occur when calling EventBus.post()
> ----------------------------------------------------------------------
>
> Key: WICKET-5619
> URL: https://issues.apache.org/jira/browse/WICKET-5619
> Project: Wicket
> Issue Type: Bug
> Components: wicket-atmosphere
> Affects Versions: 6.15.0
> Reporter: Daniel Stoch
> Assignee: Martin Grigorov
> Labels: atmosphere
> Fix For: 7.0.0-M3, 6.17.0
>
>
> ConcurrentModificationException may occur when calling EventBus.post()
> because subscriptionsForPage collection can be modified by another thread
> during a loop inside AtmosphereRequestHandler.executeHandlers:
> {code}
> java.util.ConcurrentModificationException
> at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
> at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
> at
> com.google.common.collect.AbstractMultimap$WrappedCollection$WrappedIterator.next(AbstractMultimap.java:540)
> at
> java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1102)
> at com.google.common.collect.Iterators$8.computeNext(Iterators.java:735)
> at
> com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
> at
> com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
> at
> org.apache.wicket.atmosphere.AtmosphereRequestHandler.executeHandlers(AtmosphereRequestHandler.java:79)
> at
> org.apache.wicket.atmosphere.AtmosphereRequestHandler.respond(AtmosphereRequestHandler.java:74)
> at
> org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:862)
> at
> org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
> at
> org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:261)
> at
> org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:218)
> at
> org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:289)
> at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:417)
> at
> org.apache.wicket.atmosphere.EventBus.postToSingleResource(EventBus.java:393)
> at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:346)
> at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:329)
> {code}
> I think the problem is inside in EventBus.postToSingleResource() method:
> {code}
> subscriptionsForPage = Collections2.filter(
> Collections.unmodifiableCollection(subscriptions.get(key)), new
> EventFilter(event));
> {code}
> I think collection get from "subscriptions.get(key)" should be copied first
> and then assigned to subscriptionsForPage variable. Now it is a pass as a
> reference (not directly but it is) and it can lead to
> ConcurrentModificationException.
> It is not easy to reproduce this problem (more that one thread must call post
> at the same time), but sometimes it happen.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)