在后台更新JavaFX树时出现ConcurrentModificationException

Seb*_*ies 6 java javafx-2

我的代码TreeItem<String> 在后台任务中创建,因为我有很多它们,并且它们的创建需要相当长的时间才能冻结应用程序.在这个例子中它没有多大意义,但它说明了我在实际应用程序中遇到的问题.扩展节点时,程序会抛出ConcurrentModificationException.

我使用jdk1.7.0_17和JavaFX 2.2.7

有谁知道如何创建线程安全Tree或如何规避问题?

例外

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)
    ...
Run Code Online (Sandbox Code Playgroud)

import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import java.security.SecureRandom;
import java.util.Random;


public class ConcurrentExample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        TreeView<String> treeView = new TreeView<String>(createNode("root"));
        HBox hBox = new HBox();
        hBox.getChildren().addAll(treeView);
        Scene scene = new Scene(hBox);
        stage.setScene(scene);
        stage.show();
    }

    Random r = new SecureRandom();

    public TreeItem<String> createNode(final String b) {
        return new TreeItem<String>(b) {
            private boolean isLeaf;
            private boolean isFirstTimeChildren = true;
            private boolean isFirstTimeLeaf = true;

            @Override
            public ObservableList<TreeItem<String>> getChildren() {
                if (isFirstTimeChildren) {
                    isFirstTimeChildren = false;
                    buildChildren(super.getChildren());
                }
                return super.getChildren();
            }

            @Override
            public boolean isLeaf() {
                if (isFirstTimeLeaf) {
                    isFirstTimeLeaf = false;
                    isLeaf = r.nextBoolean() && r.nextBoolean() && r.nextBoolean();
                }
                return isLeaf;
            }

            private void buildChildren(final ObservableList<TreeItem<String>> children) {
                if (!this.isLeaf()) {
                    Task<Integer> task = new Task<Integer>() {
                        @Override
                        protected Integer call() throws Exception {
                            int i;
                            int max = r.nextInt(500);
                            for (i = 0; i <= max; i++) {
                                children.addAll(new TreeItem[]{createNode("#" + r.nextInt())});
                            }
                            return i;
                        }
                    };
                    new Thread(task).start();
                }
            }
        };
    }

}
Run Code Online (Sandbox Code Playgroud)

Seb*_*ies 9

目前的答案没有帮助.关键是你必须在Platform.runLater的帮助下在主线程中执行子代的更新

import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import java.security.SecureRandom;
import java.util.Random;


public class Example extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        TreeView<String> treeView = new TreeView<String>(createNode("root"));
        HBox hBox = new HBox();
        hBox.getChildren().addAll(treeView);
        Scene scene = new Scene(hBox);
        stage.setScene(scene);
        stage.show();
    }

    Random r = new SecureRandom();

    public TreeItem<String> createNode(final String b) {
        return new TreeItem<String>(b) {
            private boolean isLeaf;
            private boolean isFirstTimeChildren = true;
            private boolean isFirstTimeLeaf = true;

            @Override
            public ObservableList<TreeItem<String>> getChildren() {
                if (isFirstTimeChildren) {
                    isFirstTimeChildren = false;
                    buildChildren(super.getChildren());
                }
                return super.getChildren();
            }

            @Override
            public boolean isLeaf() {
                if (isFirstTimeLeaf) {
                    isFirstTimeLeaf = false;
                    isLeaf = r.nextBoolean() && r.nextBoolean() && r.nextBoolean();
                }
                return isLeaf;
            }

            private void buildChildren(final ObservableList<TreeItem<String>> children) {
                if (!this.isLeaf()) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            int i;
                            int max = r.nextInt(500);
                            for (i = 0; i <= max; i++) {
                                children.addAll(new TreeItem[]{createNode("#" + r.nextInt())});
                            }
                        }
                    });
                }
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

这家伙遇到了同样的问题:http://blog.idrsolutions.com/2012/12/handling-threads-concurrency-in-javafx/