我用javafx ui编写了一个java程序来显示事务的实时计数器, 许多线程需要将更新的值写入单个标签,我这样做:
1 - " SOME_NUMBER"是主类中的整数变量(不是fx控制器类本身,让我们考虑它的名称" MainClass")定义这种方式:
public static Integer SOME_NUMBER;
2-Many Threads更新" SOME_NUMBER"的值这样:
synchronized(SOME_NUMBER){
MainClass.SOME_NUMBER--;
}
synchronized(SOME_NUMBER){
MainClass.SOME_NUMBER++;
}
3 - 最后结果以这种方式显示来自其他类:
label.setText(String.valueOf(SOME_NUMBER));
数字应该每秒更新一次,所以我不想在特定的时间间隔内使用Task
更新我的视图,而且也不想使用Platform.runLater
因为当你每秒大约有5-20笔交易时,它会显着延迟...
所以我想要一种安全的方式来实现这样的事情以满足我的需求,因为我当前的实现导致了这样的错误,我删除了ui更新所有这些都消失了:
> java.lang.NullPointerException
at com.sun.javafx.text.PrismTextLayout.createLine(Unknown Source)
at com.sun.javafx.text.PrismTextLayout.layout(Unknown Source)
at com.sun.javafx.text.PrismTextLayout.ensureLayout(Unknown Source)
at com.sun.javafx.text.PrismTextLayout.getBounds(Unknown Source)
at javafx.scene.text.Text.getLogicalBounds(Unknown Source)
at javafx.scene.text.Text.getYRendering(Unknown Source)
有没有机会使用可观察的值或类似的东西?
答案 0 :(得分:2)
如果您不想使用Task,只需稍加修改即可进行复制和粘贴,以使用与任务使用相同的技术(以下代码只是来自任务源的复制和粘贴)。
如果您知道自己的值是整数,那么您可能希望使用AtomicInteger而不是AtomicReference。
代码将为您提供一个message属性,您可以尝试从任何线程(通过updateMessage
API)更新其值,但只有在JavaFX应用程序线程准备好处理它时才会发生更新。您还可以观察属性以进行更改,并将JavaFX UI组件安全地绑定到属性,因为知道该属性本身甚至已在JavaFX应用程序线程上更新。
/**
* Used to send message updates in a thread-safe manner from the subclass
* to the FX application thread. AtomicReference is used so as to coalesce
* updates such that we don't flood the event queue.
*/
private AtomicReference<String> messageUpdate = new AtomicReference<>();
private final StringProperty message = new SimpleStringProperty(this, "message", "");
@Override public final String getMessage() { checkThread(); return message.get(); }
@Override public final ReadOnlyStringProperty messageProperty() { checkThread(); return message; }
/**
* Updates the <code>message</code> property. Calls to updateMessage
* are coalesced and run later on the FX application thread, so calls
* to updateMessage, even from the FX Application thread, may not
* necessarily result in immediate updates to this property, and
* intermediate message values may be coalesced to save on event
* notifications.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param message the new message
*/
protected void updateMessage(String message) {
if (isFxApplicationThread()) {
this.message.set(message);
} else {
// As with the workDone, it might be that the background thread
// will update this message quite frequently, and we need
// to throttle the updates so as not to completely clobber
// the event dispatching system.
if (messageUpdate.getAndSet(message) == null) {
runLater(new Runnable() {
@Override public void run() {
final String message = messageUpdate.getAndSet(null);
Task.this.message.set(message);
}
});
}
}
}
private void checkThread() {
if (started && !isFxApplicationThread()) {
throw new IllegalStateException("Task must only be used from the FX Application Thread");
}
}