title: JavaFX: ConcurrentModificationException while adding TreeItem objects in TreeView, in a seperate thread
body: <p>I have the following code</p>
  
  <pre><code>public void start(Stage primaryStage) {        
      BorderPane border_pane = new BorderPane();
  
      TreeView tree = addTreeView();                                          //TreeView on the LEFT
      border_pane.setLeft(tree);
  
      /* more stuff added to the border_pane here... */
  
      Scene scene = new Scene(border_pane, 900, 700);
      scene.setFill(Color.GHOSTWHITE);
  
      primaryStage.setTitle("PlugControl v0.1e");
      primaryStage.setScene(scene);
      primaryStage.show();
  }
  
  public static void main(String[] args) {
      launch(args);
  }
  </code></pre>
  
  <p>With <code>addTreeView</code> being a function that reads data off an SQL DB and adds around ~35 <code>TreeItem</code>s, based on that data. The addition of <code>TreeItem</code>s to <code>treeItemRoot</code> is done in a seperate thread. <strong>NOTE:</strong> <em>treeItemRoot</em> is declared in the main class, and is null before here.</p>
  
  <pre><code>public TreeView addTreeView() {                                             //Our treeView is positioned on the LEFT
          treeItemRoot = new PlugTreeItem&lt;&gt;("Active Plugs", new ImageView(new Image(getClass().getResourceAsStream("graphics/plugicon.png"))), new Plug());          //Root of the tree, contains a dummy Plug object.
          selectedTreeItem = treeItemRoot;
  
          treeItemRoot.setExpanded(true);                                         //always expand it
  
          selectedTreeItem.getPlugItem()
                  .getSIHUid().addListener(new ChangeListener&lt;String&gt;() {
                      @Override
                      public void changed(ObservableValue&lt;? extends String&gt; observable, String oldValue, String newValue
                      ) {
                          System.err.println("changed " + oldValue + "-&gt;" + newValue);
                      }
                  }
                  );
  
          TreeView&lt;String&gt; treeView = new TreeView&lt;&gt;(treeItemRoot);               //Build the tree with our root node.
  
          final Task task;
          task = new Task&lt;Void&gt;() {
              @Override
              protected Void call() throws Exception {
  
                  //=========== SQL STUFF BEGINS HERE ============================
                  Statement sta = null;
                  ResultSet result_set = null;
                  Connection conn = null;
  
                  try {
                      try {
                          System.err.println("Loading JDBC driver...");
                          Class.forName("com.mysql.jdbc.Driver");
                          System.err.println("Driver loaded!");
                      } catch (ClassNotFoundException e) {
                          throw new RuntimeException("Cannot find JDBC driver in the classpath!", e);
                      }
  
                      System.err.println("Connecting to database...");
                      conn = DriverManager.getConnection("[DB link here]", "[username]", "[password]");           //Username is PlugControl, pw is woof
                      System.err.println("Connected to Database!");
  
                      sta = conn.createStatement();
                      String sql_query = "SELECT * FROM pwnodes INNER JOIN pwcomports ON pwnodes.NetworkID = pwcomports.NetworkID WHERE pwnodes.connection = 'on' ORDER BY pwnodes.Location";
  
                      result_set = sta.executeQuery(sql_query);
                      System.err.println("SQL query successfuly executed!");
  
                      int count = 0;
                      while (result_set.next()) {
                          Plug pl = null;                                         //MARKER: We might need to do switch (result_set.getString("Server")) for SIHU1 and SIHU2.
                          count++;
                          pl = new Plug(result_set.getString("SIHUid"), result_set.getString("sensorID"), result_set.getString("Location"), result_set.getString("Appliance"), result_set.getString("Type"), result_set.getString("connection"), result_set.getString("Server"), result_set.getString("ServerIP"));
                          PlugTreeItem&lt;String&gt; pti = new PlugTreeItem(pl.getSIHUid().getValue() + " " + pl.getLocation() + " " + pl.getAppliance(), new ImageView(new Image(getClass().getResourceAsStream("graphics/smiley.png"))), pl); //icon does not work in children
                          treeItemRoot.getChildren().add(pti);                    //CONCURRENCY ERRORS HERE
                      }
                      System.err.println("ALERT SQL QUERY RESULTS: " + count);
  
                  } catch (SQLException e) //linked try clause @ line 50
                  {
                      throw new RuntimeException("Cannot connect the database!", e);
                  } finally {   //  Time to wrap things up, by closing all open SQL procs. 
                      try {
                          if (sta != null) {
                              sta.close();
                          }
                          if (result_set != null) {
                              result_set.close();
                          }
                          if (conn != null) {
                              System.err.println("Closing the connection.");
                              conn.close();
                          }
                      } catch (SQLException e) //We might as well ignore this, but just in case.
                      {
                          throw new RuntimeException("Error while closing up statement, result set and connection!", e);
                      }
                  }
  
                  //============== SQL STUFF ENDS HERE ===========================
                  System.err.println("Finished");
                  return null;
              }
          };
  
          new Thread(task).start();                                               //Run the task!
  
          treeView.getSelectionModel()
                  .selectedItemProperty().addListener(new ChangeListener() {
                      @Override
                      public void changed(ObservableValue observable, Object oldValue, Object newValue
                      ) {
                          selectedTreeItem = (PlugTreeItem&lt;String&gt;) newValue;
                          System.err.println("DEBUG: Selection plug SIHUid: " + selectedTreeItem.getPlugItem().print());           //MARKER: REMOVE
                          updateTextFields();                                             //Update TextAreas.
                          if (!"DUMMY".equals(selectedTreeItem.getPlugItem().getSIHUid().getValue())) {
                              buttonOn.setDisable(false);
                              buttonOff.setDisable(false);
                          } else {
                              buttonOn.setDisable(true);
                              buttonOff.setDisable(true);
                          }
                      }
                  }
                  );
          return treeView;
      }
  </code></pre>
  
  <p>Once every 5-6 runs I receive a <code>ConcurrentModificationException</code> because I think the Thread task() doesn't manage to finish before <code>addTreeView</code>'s returned <code>TreeView</code> is added to the border_pane, and maybe it begins iterating through it while it's still having items added to it?</p>
  
  <pre><code>Executing C:\Users\74\Documents\NetBeansProjects\PlugControl_v0.5\dist\run1559674105\PlugControl.jar using platform C:\Program Files\Java\jdk1.7.0_25\jre/bin/java
  Loading JDBC driver...
  Driver loaded!
  Connecting to database...
  Connected to Database!
  SQL query successfuly executed!
  java.util.ConcurrentModificationException
      at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
      at java.util.ArrayList$Itr.next(ArrayList.java:791)
      at com.sun.javafx.collections.ObservableListWrapper$ObservableListIterator.next(ObservableListWrapper.java:681)
      at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:788)
      at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:777)
      at javafx.scene.control.TreeView.getExpandedDescendantCount(TreeView.java:864)
      at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:873)
      at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
      at com.sun.javafx.scene.control.skin.TreeViewSkin.getItemCount(TreeViewSkin.java:207)
      at com.sun.javafx.scene.control.skin.TreeViewSkin.updateItemCount(TreeViewSkin.java:220)
      at com.sun.javafx.scene.control.skin.TreeViewSkin.handleControlPropertyChanged(TreeViewSkin.java:135)
      at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
      at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
      at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
      at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
      at javafx.beans.property.IntegerPropertyBase.fireValueChangedEvent(IntegerPropertyBase.java:123)
      at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
      at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
      at javafx.scene.control.TreeView.setTreeItemCount(TreeView.java:515)
      at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:876)
      at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
      at javafx.scene.control.TreeCell.updateItem(TreeCell.java:391)
      at javafx.scene.control.TreeCell.access$000(TreeCell.java:67)
      at javafx.scene.control.TreeCell$1.invalidated(TreeCell.java:95)
      at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
      at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
      at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
      at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
      at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
      at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
      at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:112)
      at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1596)
      at com.sun.javafx.scene.control.skin.VirtualFlow.addLeadingCells(VirtualFlow.java:1049)
      at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1005)
      at com.sun.javafx.scene.control.skin.VirtualFlow.setCellCount(VirtualFlow.java:206)
      at com.sun.javafx.scene.control.skin.TreeViewSkin.updateItemCount(TreeViewSkin.java:225)
      at com.sun.javafx.scene.control.skin.TreeViewSkin.handleControlPropertyChanged(TreeViewSkin.java:135)
      at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
      at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
      at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
      at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
      at javafx.beans.property.IntegerPropertyBase.fireValueChangedEvent(IntegerPropertyBase.java:123)
      at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
      at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
      at javafx.scene.control.TreeView.setTreeItemCount(TreeView.java:515)
      at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:876)
      at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
      at javafx.scene.control.TreeCell.updateItem(TreeCell.java:391)
      at javafx.scene.control.TreeCell.access$000(TreeCell.java:67)
      at javafx.scene.control.TreeCell$1.invalidated(TreeCell.java:95)
      at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
      at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
      at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
      at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
      at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
      at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
      at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:112)
      at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1596)
      at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1500)
      at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1523)
      at com.sun.javafx.scene.control.skin.VirtualFlow$3.call(VirtualFlow.java:478)
      at com.sun.javafx.scene.control.skin.VirtualFlow$3.call(VirtualFlow.java:476)
      at com.sun.javafx.scene.control.skin.PositionMapper.computeViewportOffset(PositionMapper.java:143)
      at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1001)
      at javafx.scene.Parent.layout(Parent.java:1018)
      at javafx.scene.Parent.layout(Parent.java:1028)
      at javafx.scene.Parent.layout(Parent.java:1028)
      at javafx.scene.Parent.layout(Parent.java:1028)
      at javafx.scene.Scene.layoutDirtyRoots(Scene.java:516)
      at javafx.scene.Scene.doLayoutPass(Scene.java:487)
      at javafx.scene.Scene.access$3900(Scene.java:170)
      at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2203)
      at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
      at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
      at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
      at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
      at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
      at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
      at java.lang.Thread.run(Thread.java:724)
  ALERT SQL QUERY RESULTS: 35
  Closing the connection.
  Finished
  </code></pre>
  
  <p>Any help/advice on dealing with the issue, guys? The exception doesn't point me towards a place in my code, and so far I'm working on hunches.}</p>
  
  <p>EDIT: For reference, <code>PlugTreeItem</code> is just a TreeItem&lt;> that also carries a <code>Plug</code> with it, Plug being a class of mine that holds a few String values. Nothing special.
  <code>public class PlugTreeItem&lt;T&gt; extends TreeItem{ \* code *\}</code></p>