JavaFX GUI多线程问题

时间:2016-01-10 16:10:09

标签: java multithreading javafx

我有一个JavaFX应用程序只有一个场景,其中一个Label假定以“hh:mm:ss”格式显示当前时间,另一个Label假定以“12 /”显示当前日期12/12“或”12-12-12“。要么没事。在控制器中,我创建了两个在初始化时调用的方法,以启动一个线程来更新两个标签。我们的想法是每隔500毫秒更新一次时钟,每隔一分钟或60000毫秒更新一次。下面显示了我正在使用的代码,除了休眠时间和正在更新的Label之外,它们基本相同。这是错误和我的代码:

WARNING: Uncaught throwable in javafx concurrent thread pool
java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4


private void startClockUpdateService() {
    Service<Void> clockBackgroundThread = new Service<Void>(){

        @Override
        protected Task<Void> createTask() {
            return new Task<Void>(){

                @Override
                protected Void call() throws Exception {
                    while(true){
                        SimpleDateFormat sdfClock = new SimpleDateFormat("hh:mm:ss");
                        String date1 = sdfClock.format(new Date());
                        timeLabel.setText(date1);
                        Thread.sleep(500);
                    }
                }

            };
        }

    };
    clockBackgroundThread.restart();
}

private void startDateUpdateService() {
    Service<Void> clockBackgroundThread = new Service<Void>(){

        @Override
        protected Task<Void> createTask() {
            return new Task<Void>(){

                @Override
                protected Void call() throws Exception {
                    while(true){
                        SimpleDateFormat sdfClock = new SimpleDateFormat("MM-dd-yyyy");
                        String date1 = sdfClock.format(new Date());
                        dateLabel.setText(date1);
                        Thread.sleep(60000);
                    }
                }

            };
        }

    };
    clockBackgroundThread.restart();
}

我注意到似乎格式“hh:mm:ss”似乎导致问题,因为当我将它换成日期格式“MM-dd-yyyy”时,一切似乎都能正常工作。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

从其他线程更新UI线程时,应始终使用Platform.runLater

对于定期操作,请考虑使用Timeline

KeyFrame update = new KeyFrame(Duration.seconds(0.5), event -> { 
    // update label here. You don't need to use Platform.runLater(...), because Timeline makes sure it will be called on the UI thread.
}); 
Timeline tl = new Timeline(update); 
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();