Как добавить функционал pause/resume/stop приложению на JavaFX?

Есть десктопное приложение, работающее на JavaFX (OpenJFX). Логика написана на связке Spring Boot + JavaFX с помощью FXWeaver. Задача заключается в следующем: клиенту нужна возможность ставить приложение на паузу/возобновлять/останавливать (по нажатию соответствующей кнопки на форме). У меня есть мысль запускать сервис в отдельном потоке (унаследовавшись от Thread), и добавить такой функционал:

  1. Pause: вызывать super.sleep(1) в цикле, пока не будет изменём флаг paused
  2. Resume: ставить флаг paused в false
  3. Stop: this.interrupt()

Не уверен, что это корректный подход к решению такой задачи, потому и пишу сюда. Можете дать парочку подсказок, как сделать правильно?


Ответы (1 шт):

Автор решения: Alexander Pavlov

wait/notify

import java.util.EnumSet;

public class MyTask {

    public static enum State {Initial, Running, Paused, Stopped};

    private final Thread worker = new Thread(this::workLoop);
    private final Object stateLock = new Object();
    private State state = State.Initial;

    private void writeState(EnumSet<State> expectedStates, State newState, Runnable onChange) {
        synchronized (stateLock) {
            if (expectedStates.contains(state)) {
                state = newState;
                onChange.run();
            }
        }
    }

    private State readState() {
        synchronized (stateLock) {
            if (state == State.Paused) {
                try {
                    stateLock.wait();
                } catch (InterruptedException e) {
                    // nothing to do
                }
            }
            return state;
        }
    }

    public void start() {
        writeState(EnumSet.of(State.Initial), State.Running, worker::start);
    }

    public void stop() {
        writeState(EnumSet.of(State.Running, State.Paused), State.Stopped, stateLock::notifyAll);
    }

    public void pause() {
        writeState(EnumSet.of(State.Running), State.Paused, stateLock::notifyAll);
    }

    public void resume() {
        writeState(EnumSet.of(State.Paused), State.Running, stateLock::notifyAll);
    }

    private void workLoop() {
        while (readState() != State.Stopped) {
            nextIteration();
        }
    }

    private void nextIteration() {
        // do some small work here and let loop to verify its state
    }
}
→ Ссылка