到目前为止,我一直在构建一个应用程序,当工作线程到达某个点或事件时,会更改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));
}
});
}
});
答案 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);
}
}