【发布时间】:2019-10-04 20:55:44
【问题描述】:
我尝试学习 kotlin,但 TornadoFX 线程有问题。
在 JavaFX 中,我可以在另一个线程中更新 observable 属性,并且更新将发生在视图中,而无需使用“Platform.runLater()”触发
更新:
我对 JFX 中的线程安全的所有假设都是错误的!
仅使用 Platform.runLater()、Tasks 或 Animationtimer 更新绑定到 UI 线程的 UI 元素或属性,切勿在没有 Platform.runLater() 的情况下从外部更新。
虽然您应该谨慎使用 Platform.runLater(),因为您无法控制何时将什么添加到 UI 线程,这可能会引起一些麻烦。
以下是我的误解:
这是 在 JavaFX 中工作正常 工作但也是错误的
@Fxml
ProgressBar progress;
@Fxml
public void initialize(){
DoubleProperty prop = new SimpleDoubleProperty(0);
progress.progressProperty().bind(prop);
ExecutorService ex = Executors.newSingleThreadExector();
ex.execute(()->{
while(true){
Thread.sleep(2000);
prop.set(prop.get()+0.1);
}
}
}
本质上是相同的代码,但在 Kotlin 中。它不起作用并抛出异常:
不在 FX 应用程序线程上; currentThread = Thread-3 TornadoFX
class test : View() {
override val root: BorderPane by fxml("/views/primary.fxml")
val counter = SimpleDoubleProperty()
val progress: ProgressBar by fxid()
init {
thread{
while(true){
Thread.sleep(2000)
counter.value += 0.1
}
}
progress.bind(counter)
}
}
我希望他们会以同样的方式工作。 我可以用“Platform.runLater(()->...)”修复它,但是当它已经观察到属性时,我不想在 UI 线程中排队所有东西。 我认为这是将某些东西绑定到 UI 元素的可能性的全部目的。
是我使用了错误的属性和绑定还是 TornadoFX 问题?
【问题讨论】:
-
不,它在 fx 中不能正常工作,即使它不会立即抛出错误和定时炸弹。我们不得从 fx 线程更新场景图中节点的属性,没有例外,没有办法绕过 周期
-
您所说的“在 JavaFX 中工作正常”是错误的。当属性绑定到 UI 元素时,您不应在另一个线程中更新属性。这将触发来自另一个线程的绑定 UI 元素的更新,这可能会导致内部 JavaFX 系统实现中的竞争条件和错误。所以你不应该那样做。绑定到 UI 的属性只能在 JavaFX 应用程序线程上更新。
-
为什么你认为来自 Observables 的通知是线程安全的?它是一个接口,我在其文档中看不到任何强制其实现保证这样的东西的东西。或者它是特定于 kotlin 绑定的东西?
-
竞态条件是由一个线程更新状态而FX线程读取状态引起的。没有适当的同步,因此不能保证 FX 线程看到正确的状态。这会导致未定义的行为。不,正如我已经提到的,
Observable的核心实现都不是线程安全的。不过,我对 TornadoFX 并不太熟悉,所以它可能会在这方面有所补充。 -
感谢您聆听并进行必要的研究 - 这就是我们所有人最有效地学习的方式:)
标签: java multithreading javafx kotlin tornadofx