JavaFX并发:修改sinle StringProperty的多个线程

时间:2014-06-09 14:48:32

标签: multithreading properties concurrency javafx

到目前为止,我一直在构建一个应用程序,当工作线程到达某个点或事件时,会更改StringProperty事件的millis时间戳。

反过来,JavaFX主线程中的侦听器侦听该属性并将时间戳输出到GUI中的TextArea

在我的工作过程中,我不得不将Worker线程的一些功能拆分为第二个Worker线程,因为它太慢了。

问题是这样的:现在我已经有两个工作人员需要"玩"使用StringProperty,我得到ConcurrentModification例外,正如预期的那样。 是否有任何方法或实现来处理,或者我必须让第二个工作人员使用第二个StringProperty(反过来,将第二个监听器附加到我的主线程,这是优先)?

编辑:对于请求听众的绅士,它是这样的:

my_monitor.getMessageProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, final String newValue) {
    //Substring because the last 13 digits is the current system milli time,
    //the measure is in place so that the observableValue always changes on an event.
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                writeToLog(newValue.substring(0, newValue.length() - 13));
            }
        });
    }
});

1 个答案:

答案 0 :(得分:1)

你的第二种方法无论如何都不会起作用。如果从后台线程修改StringProperty,将在该后台线程上调用观察它的侦听器,从而导致从后台线程更新TextArea

相反,使用StringProperty更新FX应用程序线程上的(单个)Platform.runLater()。那么你的字符串属性只能从FX应用程序线程访问,所以它实际上是单线程的。

更新:完整示例

import java.util.Random;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class WorkerSharedPropertyExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final TextArea console = new TextArea();
        final BorderPane root = new BorderPane();
        root.setCenter(console);

        final Scene scene = new Scene(root, 600, 400);

        primaryStage.setScene(scene);
        primaryStage.show();

        final StringProperty messageHolder = new SimpleStringProperty();
        messageHolder.addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) {
                console.appendText(newValue + "\n");
            }
        });

        Thread worker1 = createThread(messageHolder, "Worker 1");
        Thread worker2 = createThread(messageHolder, "Worker 2");

        worker1.start();
        worker2.start();
    }

    private Thread createThread(StringProperty messageHolder, String name) {
        final Random rng = new Random();
        Thread thread = new Thread() {
            @Override
            public void run() {
                int value = 0 ;
                try {
                    while (true) {
                        Thread.sleep(rng.nextInt(1000)+500);
                        value++; 
                        final String message = getName() + " updated status to value "+value ;
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                messageHolder.set(message);
                            }
                        });
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        };  
        thread.setName(name);
        thread.setDaemon(true);
        return thread ;
    }

    public static void main(String[] args) {
        launch(args);
    }
}