Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
ConcurrentModificationException from framework code
I'm writing this post as a generic resource to refer to whenever you're assisting someone who has problems with ConcurrentModificationException or other concurrency-related issues that seem to be caused by framework code in some com.vaadin.* package.
This is most likely a symptom of some other part of the application (i.e. not the framework) updating the state without locking the session. Run your server with assertions enabled to get help pinpointing the original issue.
Why does this happen?
Most parts of the framework are designed for single threaded use so that individual component implementations do not need to take take synchronization into account. The framework synchronizes on each VaadinSession instance to ensure that that each user's state stays consistent even when there are multiple requests or background threads attempting to make updates. Failing to acquire the appropriate lock before doing updates will in most cases work without problem since there's usually no other thread touching the same data. If some other thread also touches the data at "the same time", either of them might get a ConcurrentModificationException, go into an infinite loop or cause other undefined behavior.
Isn't there a bug in the framework when it's the last part of the stacktrace?
One of the most common symptoms of missing synchronization is that something causes a Component to be marked as "dirty" while the framework is busy creating a response to send to the browser by collecting changes from all dirty components. In such cases the thread causing the component to be marked as dirty will continue working without problems, but the framework thread will get an exception when it has collected the changes from one component and goes on to find the next dirty component. So the most common case is caused by some other part of the application, but revealed through framework code.
What do I have to do in my application?
In most cases you don't need to do anything since the framework already handles the synchronization for normal requests from the browser and all events fired in that way. If your application does some work in the background (e.g. using a worker thread or an asynchronous message bus) or if you're updating one user's data in response to events from another user, you should use the UI.access method to tell the framework which parts of the code should only be run with the user's application state locked.
How can I find out what's wrong if the stacktrace is from a thread that has properly acquired the lock?
Most of the framework code that expects to be run with the session locked will also check that this is the case, but since this check has some performance overhead, it is only done when the JVM is configured with assertions enabled. To enable assertions, "-ea" must be set as a JVM parameter when the server is started. Please conslut documentation for your application server for information on how to do this. To help you verify that you server is actually running with assertion checks enabled, it can be helpful to temporarily add e.g. a Button to your UI with a click listener that runs "assert false;". Clicking that button will cause an exception stacktrace to be logged only if assertions are enabled.
What if I can't find anything in my application that would cause this?
Based on experience, most cases of ConcurrentModificationException are caused by omitted locking in application code or a thrid party add-on. Running the server with assertions enabled helps pinpointing the modification that causes another thread to get into problems. If that is not the case, there might of course be a bug somewhere in the framework, so please report anything suspicious as a ticket to dev.vaadin.com.
Couldn't the framework use e.g. ConcurrentHashSet instead of the regular HashSet?
Changing the framework's internal data structures to use e.g. ConcurrentHashSet and CopyOnWriteArrayList that can maintain its own internal state without locking would not really solve anything since it would only guarantee that the data structure is internally consistent - there would still not be any guarantees that different structures would be in sync with each other. It would also mean that all components (including almost all add-ons) would then have to be implemented to support concurrent access, thus making it much more difficult to create new components.
Leif this is great stuff, thanks!