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
添加回答
舉報