JDK-8096583 : ConcurrentModificationException when closing APPLICATION_MODAL dialog
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8u25,8u40
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-12-03
  • Updated: 2015-07-24
  • Resolved: 2015-06-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u60Fixed 9Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
I have the very latest JRE 8 Update 40 b16 (32bit).

My application uses lots of JavaFX Dialogs, and for some dialogs, when I call showAndWait(), under some circumstances that are unknown to myself... I get this exception:

Exception in thread "JavaFX Application Thread" 
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
	at java.util.ArrayList$Itr.next(Unknown Source)
	at com.sun.javafx.tk.quantum.GlassStage.windowsSetEnabled(Unknown Source)
	at com.sun.javafx.tk.quantum.WindowStage.setVisible(Unknown Source)
	at javafx.stage.Window$9.invalidated(Unknown Source)
	at javafx.beans.property.BooleanPropertyBase.markInvalid(Unknown Source)
	at javafx.beans.property.BooleanPropertyBase.set(Unknown Source)
	at javafx.stage.Window.setShowing(Unknown Source)
	at javafx.stage.Window.show(Unknown Source)
	at javafx.stage.Stage.show(Unknown Source)
	at javafx.stage.Stage.showAndWait(Unknown Source)
	at javafx.scene.control.HeavyweightDialog.showAndWait(Unknown Source)
	at javafx.scene.control.Dialog.showAndWait(Unknown Source)

I cannot for the life of me figure out if it's me doing something wrong, or if this is indeed a bug in JavaFX dialogs.. but I am leaning towards a JavaFX bug.

I do not have a test case, since it's my real application in which it happens... and most of the dialogs show just fine.
Comments
http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/5c4ee9cb5661
10-06-2015

learned something (#2). Would not have thought of that. +1
10-06-2015

http://cr.openjdk.java.net/~kcr/RT-39569/webrev.00/ When an application-modal dialog is closed, we iterate over the list of windows and enable them to receive input events. The problem occurs because a child window of a modal window, such as a context menu or other popup, will be closed as a result of closing the dialog and can be removed from the list of windows while we are iterating it. The solution is: 1) Iterate over a copy of the windows list 2) For each window, check that it is still in the list before enabling it This follows the same pattern used in requestClosingAllWindows() which is the only other method that iterates over the windows list. Tested with the test case attached to RT-40516. Without the fix, we get a CME every time. With the fix it runs as expected. I also ran a full set of unit test, including the modality tests, and ran HelloModality, HelloDialogs, and HelloAlert.
10-06-2015

non regression for 8u60
09-06-2015

I can reproduce this consistently using the test case in RT-40516.
08-06-2015

See RT-40516 for another test case that hits this bug.
17-04-2015

Here's a workaround for anyone who's interested: import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.event.EventType; import javafx.stage.Stage; import com.sun.javafx.stage.StageHelper; public class ModalStageUtil { private final EventHandler allEventsFilter; private final ObservableList<Stage> stages; private final Stage modalStage; private final ListChangeListener<Stage> stagesListChangedListener; public ModalStageUtil(Stage modalStage) { this.modalStage = modalStage; this.allEventsFilter = event -> event.consume(); this.stages = StageHelper.getStages(); this.stagesListChangedListener = this::stagesChanged; } public void disableAllStages() { stages.forEach(this::disableStage); stages.addListener(stagesListChangedListener); } private void stagesChanged(ListChangeListener.Change<? extends Stage> c) { while (c.next()) { if (c.wasAdded()) { c.getAddedSubList().forEach(this::disableStage); } } } private void disableStage(Stage stage) { if (stage != modalStage) { stage.addEventFilter(EventType.ROOT, allEventsFilter); } } public void enableAllStages() { stages.forEach(this::enableStage); stages.removeListener(stagesListChangedListener); } private void enableStage(Stage stage) { stage.removeEventFilter(EventType.ROOT, allEventsFilter); } } It blocks all events to other stages (also new stages that are created while the modal stage is open). You then create your stage that should be modal: Stage stage = new Stage(); ModalStageUtil modalityUtil = new ModalStageUtil(stage); modalityUtil.disableAllStages(); stage.setOnHiding(event -> modalityUtil.enableAllStages()); stage.showAndWait(); modalityUtil.enableAllStages(); Do NOT use stage.initModality(Modality.APPLICATION_MODAL);
22-01-2015

Great. Glad to have helped.
03-12-2014

I'm going to leave this bug open even without a test case. Now that I know what's happening, I will try to construct a test that shows the bug. I will target this for 8u60.
03-12-2014

It looks like we posted a comment at roughly the same time. The bug is in the following code: for (GlassStage window : windows) { if (window != this) { window.setPlatformEnabled(enabled); } } my guess is that caling window.setPlatformEnabled can, in some circumstances, call back into GlassStage and modify (add to or remove from) the list of "windows".
03-12-2014

Thanks. I can see the code that might be the source of the problem, and it hasn't changed for a while, so it makes sense that it would happen with 8u25 as well. The code in question is run when an APPLICATION_MODAL window is shown.
03-12-2014

I seem to have accidentally found a "workaround", that will possibly help find out the root cause: dlg.initModality(Modality.WINDOW_MODAL); No exceptions anymore.
03-12-2014

Just for you to know that the problem exists in Java 8 Update 25 with openjfx-dialogs-1.0.2.jar, if that's any help...
03-12-2014

OK. Some more information I just noticed.. For normal toolbar buttons, the exception is never thrown. It happens only when I click/double-click nodes that live in a somewhat complex scene. My nodes open up a dialog when I double-click them. I simply use setOnMouseClicked() to show the dialog... My nodes extend from a Parent. The "containment hierachy" goes something like this for these nodes: Pane -> Group -> ScrollPane -> StackPane -> HiddenSidesPane. Perhaps the HiddenSidesPane is to blame? I will test this more..
03-12-2014

Since all window show / hide methods must be called on the JavaFX application thread, this isn't a multi-threading issue. What is likely happening is that the "windows" list is being modified reentrantly while being iterated. This would almost certainly be a JavaFX bug rather than an app bug.
03-12-2014

I will take a look at the stack trace, but without a reproducible test case, I will likely need to mark this as incomplete.
03-12-2014

This does not meet the criteria for a P1 bug. Lowering to P3 until we can evaluate it.
03-12-2014