Подождите определенное время, но не мешайте другим функциям приложения. - PullRequest
0 голосов
/ 11 февраля 2019

В моей игре я собираюсь реализовать функцию, которая линейно изменяет значение переменной в течение 5 секунд с 100 на 0. Игрок должен запустить функцию, нажав кнопку.

СначалаЯ хотел сделать это просто с помощью цикла for с TimeUnit.MILLISECONDS.sleep() и уменьшением значения внутри него:

for (int i = 0; i <= 100; i++) {
    decrementBatteryLevel();
    try {
        TimeUnit.MILLISECONDS.sleep(50);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Но я быстро обнаружил, что это приведет к остановке всей моей игры на 5 секунд.что не то, что я хочу.Поэтому первое, что я на самом деле попробовал, - это создание потока, выполняющего цикл for:

private Thread useBattery = new Thread(() -> {
    for (int i = 0; i <= 100; i++) {
        decrementBatteryLevel();
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});

И вызов его при необходимости:

useBattery.start();

Это сработало, но только для первогозапуск.Второй запуск потока useBattery привел к выбрасыванию java.lang.IllegalThreadStateException игрой.

Я понял, что не могу запустить поток, который уже жив, поэтому я попытался сделать это:

if (useBattery.isAlive()) {
    useBattery.interrupt();
}
useBattery.start();

Но я закончил тем, что java.lang.IllegalThreadStateException снова бросили./ * Является ли тема одноразовым продуктом ...?* /

Последнее, что я попробовал и на самом деле сработало, - это создание нового потока каждый раз, когда мне было нужно.Итак, вот что у меня сейчас есть:

new Thread(() -> {
    for (int i = 0; i <= 100; i++) {
        decrementBatteryLevel();
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

Результат этого удовлетворительный, но я боюсь, что, делая это, я быстро заполняю ОЗУ ненужными, «израсходованными» потоками.Есть ли способ сделать это лучше?

Спасибо.

1 Ответ

0 голосов
/ 11 февраля 2019

Используйте ExecutorService для запуска задач.

Executors.newSingleThreadExecutor();

Затем вы можете submit ваш Runnable или Callable, чтобы получить соответствующий Future.

final Future<?> submittedResult = executorService.submit(() -> { /* Your code */ });

При запуске нового экземпляра задачи просто cancel и submit

submittedResult.cancel(true);
executorService.submit(() -> { /* Your code */ });

Я думаю, вы можете расширить мой ответ для вашего конкретного варианта использования.
Также см. https://techblog.bozho.net/interrupting-executor-tasks/

...