如何确保在JavaFX

时间:2015-10-05 14:40:21

标签: concurrency javafx-8

我正在使用ScheduledService来确保在应用程序打开时服务器连接保持活动状态,并且用户没有主动与应用程序交互。

有些时候应用程序线程在应用程序关闭时没有结束,我假设它可能是导致我的问题的ScheduledService。

由于我的应用程序将包含多个阶段,因此我无法在窗口关闭时停止服务。有没有其他方法可以在线程执行期间查看某个阶段当前是否已打开,是否取消该服务?

//Service set up
service = new KeepSessionAliveService() ;
service.setPeriod(Duration.minutes(REPEAT_PERIOD));
service.setDelay(Duration.minutes(INITIAL_DELAY));
service.start();

private class KeepSessionAliveService extends ScheduledService<Void> {
    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws ClientProtocolException, IOException {
                pingServerToKeepAlive();
                return null;
            }
        };
    }
}

如果这不是最好的处理方式,我愿意接受建议。

感谢。

编辑: 我试图提供服务器访问的默认实现,其中开发人员只需调用提供所需的预期类定义的包装器方法。调用调用时,它将在进程运行时提供进度警报,然后在完成后关闭它。最初我尝试了一项服务,但似乎无法让它工作,因此建议尝试以下方法:

public <T> void executeServerCall(ServiceRequest serviceRequest, String message, Stage stage, Class<T> valueType, Consumer<T> success, Consumer<Exception> failure) {
    Alert progressAlert = displayProgressDialog(message, stage);
    Executors.newSingleThreadExecutor().execute(() -> {
           try {
               T result = executeServerCall(serviceRequest, valueType);
               Platform.runLater(() ->
                {
                    forcefullyHideDialog(progressAlert);
                    success.accept(result);
                });
            } catch (Exception e) {
                Platform.runLater(() ->
                {
                    forcefullyHideDialog(progressAlert);
                    failure.accept(e);
                });
            }

    });
}

根据您的回复,我确实证明正是这段代码正在运行应用程序线程,而不是服务。如果我能在这一点上完成我所需要的服务,我会非常乐意改变它。但是我找不到办法来做到以下几点:

public <T> void executeServerCall(ServiceRequest serviceRequest, String message, Stage stage, Class<T> valueType, Consumer<T> success, Consumer<Exception> failure) {

    Service<valueType> service = ....

2 个答案:

答案 0 :(得分:1)

您正在创建许多单线程执行程序,您在其上执行对服务器的每个单独调用。每个执行程序都创建自己的非守护程序线程,然后等待下一个runnable执行。

如果所有这些对服务器的调用都应该发生在一个线程上,那么你应该创建一个执行器来执行此操作。 (实际上,如果你希望它们发生在多个线程上,你仍然应该创建一个执行器,只使用多个线程,而不是一个线程。)

所以:

private final ExcecutorService serverCallExec = Executors.newSingleThreadedExecutor();

// ...

public <T> void executeServerCall(ServiceRequest serviceRequest, String message, Stage stage, Class<T> valueType, Consumer<T> success, Consumer<Exception> failure) {
    Alert progressAlert = displayProgressDialog(message, stage);
    serverCallExec.execute(() -> {
           try {
               T result = executeServerCall(serviceRequest, valueType);
               Platform.runLater(() ->
                {
                    forcefullyHideDialog(progressAlert);
                    success.accept(result);
                });
            } catch (Exception e) {
                Platform.runLater(() ->
                {
                    forcefullyHideDialog(progressAlert);
                    failure.accept(e);
                });
            }

    });
}

要让执行程序在应用程序关闭时终止其线程,请安排从serverCallExec.shutdown();方法调用Application.stop(),或者通过指定线程工厂使执行程序使用的线程成为守护程序线程:

private final ExecutorService serverCallExec = Executors.newSingleThreadedExecutor((Runnable r) -> {
    Thread t = new Thread(r);
    t.setDaemon(true);
    return t ;
});

答案 1 :(得分:0)

感谢您的建议 当我们来回走动时,我尝试了这个。

public <T> void executeServerCall(ServiceRequest serviceRequest, String message, Stage stage, Class<T> valueType, Consumer<T> success, Consumer<Throwable> failure) {
    Service<T> service = new Service<T>(){
        @Override
        protected Task<T> createTask() {
            return new Task<T>() {
                @Override
                protected T call() throws Exception {
                    return executeServerCall(serviceRequest, valueType);
                }
            };
        }
    };
    service.setOnSucceeded(event -> success.accept(service.getValue()));
    service.setOnFailed(event -> failure.accept(service.getException()));

    ProgressDialog pd = new ProgressDialog(service);
    pd.setContentText(message);
    pd.initModality(Modality.WINDOW_MODAL);
    pd.initOwner(stage);

    service.start();
}

这解决了我的问题并使用并发服务来处理我的问题。我不确定为什么以前这不起作用(我可能在创建服务时有一些奇怪的设置)。

这是一个更好的解决方案,你上面发布的那个我的需求?我只想抽象出呼叫的管道。这似乎是这样做的。