TabPane fails to initialize in a background thread when adding a series, throwing a ConcurrentModificationException.
To reproduce, use the newly developed NodeInitializationStressTest:
```
@Test
public void tabPane() {
test(() -> {
TabPane c = new TabPane();
c.setSkin(new TabPaneSkin(c));
c.getTabs().setAll(createTabs());
return c;
}, (c) -> {
c.getTabs().setAll(createTabs());
accessControl(c);
});
}
```
Exception:
java.util.ConcurrentModificationException
at java.base/java.util.AbstractList$Itr.checkForComodification(AbstractList.java:401)
at java.base/java.util.AbstractList$Itr.next(AbstractList.java:370)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.next(VetoableListDecorator.java:706)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin$TabHeaderArea.getTabHeaderSkin(TabPaneSkin.java:1033)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin$TabHeaderArea.removeTab(TabPaneSkin.java:1017)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin.lambda$8(TabPaneSkin.java:518)
at javafx.graphics/javafx.animation.Animation.runHandler(Animation.java:1147)
at javafx.graphics/javafx.animation.Animation.finished(Animation.java:1141)
at javafx.graphics/javafx.animation.AnimationAccessorImpl.finished(AnimationAccessorImpl.java:49)
at javafx.graphics/com.sun.scenario.animation.shared.SingleLoopClipEnvelope.timePulse(SingleLoopClipEnvelope.java:107)
at javafx.graphics/javafx.animation.Animation.doTimePulse(Animation.java:1234)
at javafx.graphics/javafx.animation.Animation$1.timePulse(Animation.java:190)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer.timePulseImpl(AbstractPrimaryTimer.java:316)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer$MainLoop.run(AbstractPrimaryTimer.java:239)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:588)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:572)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:565)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$6(QuantumToolkit.java:346)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
## Root Cause
Animation gets started in a background thread, which causes the animation handler to run in the FX application thread, thus creating simultaneous access to the control's fields (list of children in this case).
## Solution
Skip the animation.
To reproduce, use the newly developed NodeInitializationStressTest:
```
@Test
public void tabPane() {
test(() -> {
TabPane c = new TabPane();
c.setSkin(new TabPaneSkin(c));
c.getTabs().setAll(createTabs());
return c;
}, (c) -> {
c.getTabs().setAll(createTabs());
accessControl(c);
});
}
```
Exception:
java.util.ConcurrentModificationException
at java.base/java.util.AbstractList$Itr.checkForComodification(AbstractList.java:401)
at java.base/java.util.AbstractList$Itr.next(AbstractList.java:370)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.next(VetoableListDecorator.java:706)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin$TabHeaderArea.getTabHeaderSkin(TabPaneSkin.java:1033)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin$TabHeaderArea.removeTab(TabPaneSkin.java:1017)
at javafx.controls/javafx.scene.control.skin.TabPaneSkin.lambda$8(TabPaneSkin.java:518)
at javafx.graphics/javafx.animation.Animation.runHandler(Animation.java:1147)
at javafx.graphics/javafx.animation.Animation.finished(Animation.java:1141)
at javafx.graphics/javafx.animation.AnimationAccessorImpl.finished(AnimationAccessorImpl.java:49)
at javafx.graphics/com.sun.scenario.animation.shared.SingleLoopClipEnvelope.timePulse(SingleLoopClipEnvelope.java:107)
at javafx.graphics/javafx.animation.Animation.doTimePulse(Animation.java:1234)
at javafx.graphics/javafx.animation.Animation$1.timePulse(Animation.java:190)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer.timePulseImpl(AbstractPrimaryTimer.java:316)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer$MainLoop.run(AbstractPrimaryTimer.java:239)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:588)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:572)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:565)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$6(QuantumToolkit.java:346)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
## Root Cause
Animation gets started in a background thread, which causes the animation handler to run in the FX application thread, thus creating simultaneous access to the control's fields (list of children in this case).
## Solution
Skip the animation.
- blocks
-
JDK-8348987 ☂ Thread safety in Node initialization
-
- In Progress
-
- is cloned by
-
JDK-8349105 Pagination: exception initializing in a background thread
-
- Resolved
-
- links to
-
Commit(master) openjdk/jfx/d1f5ea81
-
Review(master) openjdk/jfx/1699