1 回答

TA贡献2080条经验 获得超4个赞
首先,重要的是要记住,不允许在 JavaFX 应用程序线程以外的任何线程中更改 JavaFX 节点。因此,您的线程需要移动以下行:
playerButton.setDisable(false);
refreshButton.setDisable(false);
refreshButton.setText("Refresh");
到一个可运行的,它被传递给平台。
Platform.runLater(() -> {
playerButton.setDisable(false);
refreshButton.setDisable(false);
refreshButton.setText("Refresh");
});
请注意,对一个线程中的字段所做的更改在另一个线程中可能不可见,除非声明为 。从 Java 语言规范:TurnPolling.closedGamevolatile
例如,在下面的(损坏的)代码片段中,假定这是一个非字段:this.donevolatileboolean
while (!this.done)
Thread.sleep(1000);
编译器可以自由地读取该字段一次,并在每次执行循环时重用缓存的值。这意味着循环永远不会终止,即使另一个线程更改了 的值。this.donethis.done
使用任务和服务
JavaFX为所有这些提供了一个更干净的解决方案:任务和服务。
服务创建任务。服务具有可绑定的值属性,该属性始终等于最近创建的任务的值。您可以将按钮属性绑定到服务的值属性:
int user_id = 0;
Service<Boolean> turnPollService = new Service<Boolean>() {
@Override
protected Task<Boolean> createTask() {
return new Task<Boolean>() {
@Override
protected Boolean call()
throws InterruptedException {
updateValue(true);
String gamePin = Context.getContext().getGamePin();
while (!GameConnection.yourTurn(user_id, gamePin)) {
Thread.sleep(5000);
if (TurnPolling.closedGame){
break;
}
}
return false;
}
};
}
};
playerButton.disableProperty().bind(turnPollService.valueProperty());
refreshButton.disableProperty().bind(turnPollService.valueProperty());
refreshButton.textProperty().bind(
Bindings.when(
turnPollService.valueProperty().isEqualTo(true))
.then("Waiting for your turn\u2026")
.otherwise("Refresh"));
当玩家的回合完成时,您将调用 。turnPollService.restart();
无论您是使用服务,还是仅使用 Platform.runLater,您仍然需要通过创建它或将所有对它的访问包含在块(或锁保护)中来使线程安全。TurnPolling.closedGamevolatilesynchronized
添加回答
举报