1 回答

TA貢獻(xiàn)2080條經(jīng)驗(yàn) 獲得超4個(gè)贊
首先,重要的是要記住,不允許在 JavaFX 應(yīng)用程序線程以外的任何線程中更改 JavaFX 節(jié)點(diǎn)。因此,您的線程需要移動(dòng)以下行:
playerButton.setDisable(false);
refreshButton.setDisable(false);
refreshButton.setText("Refresh");
到一個(gè)可運(yùn)行的,它被傳遞給平臺(tái)。
Platform.runLater(() -> {
playerButton.setDisable(false);
refreshButton.setDisable(false);
refreshButton.setText("Refresh");
});
請(qǐng)注意,對(duì)一個(gè)線程中的字段所做的更改在另一個(gè)線程中可能不可見,除非聲明為 。從 Java 語言規(guī)范:TurnPolling.closedGamevolatile
例如,在下面的(損壞的)代碼片段中,假定這是一個(gè)非字段:this.donevolatileboolean
while (!this.done)
Thread.sleep(1000);
編譯器可以自由地讀取該字段一次,并在每次執(zhí)行循環(huán)時(shí)重用緩存的值。這意味著循環(huán)永遠(yuǎn)不會(huì)終止,即使另一個(gè)線程更改了 的值。this.donethis.done
使用任務(wù)和服務(wù)
JavaFX為所有這些提供了一個(gè)更干凈的解決方案:任務(wù)和服務(wù)。
服務(wù)創(chuàng)建任務(wù)。服務(wù)具有可綁定的值屬性,該屬性始終等于最近創(chuàng)建的任務(wù)的值。您可以將按鈕屬性綁定到服務(wù)的值屬性:
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"));
當(dāng)玩家的回合完成時(shí),您將調(diào)用 。turnPollService.restart();
無論您是使用服務(wù),還是僅使用 Platform.runLater,您仍然需要通過創(chuàng)建它或?qū)⑺袑?duì)它的訪問包含在塊(或鎖保護(hù))中來使線程安全。TurnPolling.closedGamevolatilesynchronized
添加回答
舉報(bào)