void () { List<NodeChange> nodeChanges; synchronized (modelToSwingNodeChanges) { nodeChanges = new ArrayList<>(modelToSwingNodeChanges); modelToSwingNodeChanges.clear(); } IntList indicesToFire = new IntArrayList(); List<Node> nodesToFire = new ArrayList<>(); //first grouping changes by parent node Map<Node, List<NodeChange>> groupByParent = nodeChanges.stream().collect(Collectors.groupingBy(NodeChange::getParentNode)); for (Map.Entry<Node, List<NodeChange>> entry : groupByParent.entrySet()) { Node parentNode = entry.getKey(); synchronized (parentNode) { List<NodeChange> changes = entry.getValue(); List<NodeChange> addedToThisNode = new ArrayList<>(); //removing node for (NodeChange change : changes) { if (change.nodeChangeType.equals(NodeChangeType.REMOVED) || change.nodeChangeType.equals(NodeChangeType.REPLACED)) { GroupNode grandParent = (GroupNode)parentNode.getParent(); int index = grandParent.getSwingChildren().indexOf(parentNode); if (index >= 0) { grandParent.getSwingChildren().remove(parentNode); myModel.nodesWereRemoved(grandParent, new int[]{index}, new Object[]{parentNode}); myModel.fireTreeStructureChanged(grandParent, myModel.getPathToRoot(parentNode), new int[]{index}, new Object[]{parentNode}); if (parentNode instanceof UsageNode) { grandParent.incrementUsageCount(-1); } //if this node was removed than we can skip all the other changes related to it break; } } else { addedToThisNode.add(change); } } //adding children nodes in batch if (!addedToThisNode.isEmpty()) { for (NodeChange change : addedToThisNode) { Node childNode = change.childNode; if (childNode == null) { continue; } synchronized (childNode) { List<Node> swingChildren = ((GroupNode)parentNode).getSwingChildren(); boolean contains = swingChildren.contains(childNode); if (!contains) { nodesToFire.add(childNode); parentNode.insertNewNode(childNode, 0); swingChildren.sort(COMPARATOR); indicesToFire.add(swingChildren.indexOf(change.childNode)); if (childNode instanceof UsageNode) { ((GroupNode)parentNode).incrementUsageCount(1); } } } if (!indicesToFire.isEmpty()) { myModel.fireTreeNodesInserted(parentNode, myModel.getPathToRoot(parentNode), indicesToFire.toIntArray(), nodesToFire.toArray(new Node[0])); indicesToFire.clear(); nodesToFire.clear(); } } } } } }