Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
624 views
in Technique[技术] by (71.8m points)

java - Multi-Threading error when binding a StringProperty

I have a question about multi-threading and the binding of a StringProperty.

I have a class CacheManager, which contains a Thread which updates my cache with the changes on the server. Now, I want to notify the user with a text and percentage of the progress (which are a Label and ProgressBar in JavaFX). I use public static DoubleProperty and StringProperty for this, which are defined in the CacheManager class. I just bind it like this:

progressBar.progressProperty().bind(CacheManager.progress);
someLabel.textProperty().bind(CacheManager.status);

Now, in the Updater thread, I update these Properties. With DoubleProperty this works just fine, and the ProgressBar is showing the progress perfectly. However, updating the Label with the status (which is the text from the StringProperty) throws an error: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9

Now, my question is: Why does the DoubleProperty work just fine, while the StringProperty throws an error? What is the difference between them considering multi-threading?

Any ideas on a redesign are also welcome and any help is greatly appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It is wrong to call code that results in changes to the UI from a thread other than the FX Application Thread, regardless of whether or not it throws an exception. The FX toolkit makes a best effort to throw an exception if you violate this rule, but in some cases the effect on performance is too great to perform the check. If you create these bindings, then any subsequent changes to the properties to which you have bound must be executed on the FX Application Thread. I.e., if you are running in a background thread, you must change the properties with code like:

Platform.runLater(() -> CacheManager.progress.set(...));

and

Platform.runLater(() -> CacheManager.status.set(...));

Since you probably don't want your service code to be tied to JavaFX (via the Platform class), you could consider using listeners instead of bindings, and scheduling the updates from the listeners:

CacheManager.progress.addListener((obs, oldValue, newValue) -> 
    Platform.runLater(() -> progressBar.setProgress(newValue.doubleValue())));
CacheManager.status.addListener((obs, oldStatus, newStatus) -> 
    Platform.runLater(() -> someLabel.setText(newStatus)));

If you replace the bindings with these listeners, then you are free to update the properties on any thread.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...