【问题标题】:JAVA ScheduledExecutorService only runs once when calling a Task<V>JAVA ScheduledExecutorService 仅在调用 Task<V> 时运行一次
【发布时间】:2018-04-06 22:06:50
【问题描述】:

当我将逻辑放在 Runnable 中时,它工作得很好,只是我无法与 UI 线程交互。所以我试图把所有东西都放在一个扩展 Task 的类中,它可以工作,除了任务只执行一次。没有错误,我从 Task succeeded 方法中收到一条成功消息。

我也尝试在调用方法中使任务返回布尔值 true,但这没有帮助。

public class Main extends Application { 
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{   
        SyncTask syncTask = new SyncTask();

        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        executor.scheduleAtFixedRate(syncTask, 0, 10, TimeUnit.SECONDS);

        Label syncEngineLabel = centralController.getScheduleTabMessageLabel();
        syncEngineLabel.textProperty().bind(syncTask.messageProperty());
    }
    class SyncTask extends Task<Void>{
        private Schedule schedule = null;

        public SyncTask() {}

        @Override
        protected Void call() throws Exception {
            System.out.println("we are in the task...");
            if (getScheduleFromApi()){
                updateMessage("New Schedule Retrieved...");
            }
            return null;
        }
        @Override protected void succeeded() {
            super.succeeded();
            System.out.println("succeeded");
        }

        @Override protected void cancelled() {
            super.cancelled();
            System.out.println("cancelled");
        }

        @Override protected void failed() {
            super.failed();
            System.out.println("failed");
        }

        private Boolean getScheduleFromApi(){
            Gson gson = new GsonBuilder().serializeNulls().create();
            ApiGet api = new ApiGet("schedule/get-schedule-by-room", parameters);
            api.sendRequest();

            if (api.isSuccess()){
                schedule = gson.fromJson(api.response(), Schedule.class);
                if (schedule.getStatus().equals("200")){
                    return true;
                }
                else{
                    updateMessage(schedule.getMsg());
                    return false;
                }
            }
            else {
                updateMessage("Failed to process API call to ASI Server.");
                return false;
            }
        }
    }
}

请注意,此代码实际上存在于控制器中,但我将其放在 Main 中以尝试提供自包含代码。

谢谢!

【问题讨论】:

  • 您正试图多次执行同一个任务实例。
  • 当我尝试 (?instantiate?) 在执行器内部时,它说表达式是预期的。如何为每次执行创建一个新实例?为什么我不能一遍又一遍地运行同一个实例? executor.scheduleAtFixedRate(SyncTask, 0, 10, TimeUnit.SECONDS);
  • 根据documentation,您不能重复使用Task。 (基本上,从SUCCEEDEDREADY 等会违反Task 类的状态转换规范。)使用ScheduledService
  • ok.. 有没有办法让我在执行程序中创建一个新实例,还是我需要创建一个被调用并创建实例的方法?

标签: java javafx-8 scheduled-tasks


【解决方案1】:

ScheduledExecutorService 将简单地将您提供的任务视为Runnable,并尝试在每次运行时重用相同的任务实例,这在documentation 中是明确禁止的。

改用ScheduledService

@Override
public void start(Stage primaryStage) throws Exception{   

    ScheduledService<Void> scheduledService = new ScheduledService<Void>() {
        @Override
        protected Task<Void> createTask() {
            return new SyncTask();
       }
    };
    scheduledService.setPeriod(Duration.seconds(10));
    scheduledService.start();

    Label syncEngineLabel = centralController.getScheduleTabMessageLabel();
    scheduledService.stateProperty().addListener((obs, oldState, newState) -> {
            if (newState == Worker.State.RUNNING) {
                syncEngineLabel.setText("Sync in progress");
            } else if (newState == Worker.State.FAILED) {
                syncEngineLabel.setText("Sync error");
            } else {
                syncEngineLabel.setText("Sync complete");
            }
    });


}

【讨论】:

  • 感谢 James_D。我不得不将 Task 更改为 SyncTask。我唯一的另一个问题,(我是线程新手)如果启动的任务之一长时间运行,新创建的任务会进入等待队列等待第一个任务完成还是会在自己的线程上启动?
  • @DanielH。前者(它等待)。根据文档:“ScheduledService 将保持在 [SCHEDULED] 状态的时间量取决于上次状态转换到RUNNING 与当前时间和周期之间的时间量。。 .. 如果上一次执行在期限到期之前完成,则ScheduledService 将保持SCHEDULED 状态直到期限到期。另一方面,如果执行时间超过指定期限,则ScheduledService 将立即转换回RUNNING。"
  • 知道了。我希望这不是烦人,但还有一个问题。知道为什么没有更新 messageProperty 吗?我的标签什么也没得到。
  • @DanielH。我相信当服务未运行任务时,Service 的消息属性会重置为null。由于您仅在任务退出之前立即更新任务的消息,因此您看不到任何内容。您可能希望改为观察服务的状态:请参阅更新以回答。
  • 啊..知道它重置为 null 消除了我的困惑。听者有帮助。我会玩弄它。再次感谢!!!!!!!
猜你喜欢
  • 2017-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多