Executors. Как прекращать работу потоков?

308
24 октября 2021, 19:50

Я делаю некий таймер. При его запуске выполняется какая-то последовательность действий, после чего поток должен закрыться и не грузить дальнейшую работу программы. Как мне его адекватно остановиться, я что-то не могу сообразить. Тренировался останавливать поток на данном примере. Грубо говоря перезапускать его у меня получается, а вот с полным его прерыванием возникают проблемы, как это можно решить? Еще есть такой вопрос, возможно ли в методе repeatTimer не завершать и создавать поток, а просто перезапускать (заставить отсчитать эти 5 секунд заново)? Просто в моей реализации это выглядит слишком топорно.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Solution {
    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
        for (int i = 1; i <= 15; i += 1) {
            System.out.println(i);
            if (i == 3) {
                timer.schedule(new RunTimer(), 5, TimeUnit.SECONDS);
            }
            if (i == 7) {
                timer = repeatTimer(timer);
            }
            Thread.sleep(1000);
        }
    }
        public static void dropTimer (ScheduledExecutorService timer) {
            timer.shutdownNow();
        }
        public static ScheduledExecutorService repeatTimer (ScheduledExecutorService timer) {
            dropTimer(timer);
            return startTimer();
        }
        public static ScheduledExecutorService startTimer () {
            ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
            timer.schedule(new RunTimer(), 5, TimeUnit.SECONDS);
             return timer;
        }
        static class RunTimer implements Runnable {
            @Override
            public void run() {
                System.out.println("TIMER");
            }
        }
}
Answer 1

Там есть метод scheduleAtFixedRate, которsый позволяет исполнять задачу с интервалом, а не один раз.

Первый способ - тут возможны гонки, если runnable выполняется очень быстро, маленький интервал и малое число повторений, то Ява может не успеть проставить ссылку в self

public static void execute(ScheduledExecutorService executor, final Runnable runnable, int times, long interval, TimeUnit timeUnit) {
    final AtomicInteger counter = new AtomicInteger(times);
    final AtomicReference<ScheduledFuture> self = new AtomicReference<>();
    final Runnable wrapper = new Runnable() {
        try {
            runnable.run();
        } finally {
            if (counter.decrementAndGet() == 0) {
                self.get().cancel();
            }
        }
    };
    self.set(executor.scheduleAtFixedRate(wrapper, interval, interval, timeUnit));
    // return self.get(); // Опционально можно получить доступ к задаче и управлять её жизненным циклом
}    

Второй способ - гонок нет, но и в отличие от первого, нельзя наружу вернуть ScheduledFuture и получить дополнительный контроль на жизнью задачи.

public static void execute(final ScheduledExecutorService executor, final Runnable runnable, final int times, long interval, TimeUnit timeUnit) {
    final Runnable wrapper = new Runnable() {
        try {
            runnable.run();
        } finally {
            if (times > 1) {
                execute(executor, runnable, times-1, interval, timeUnit);
            }
        }
    };
    executor.schedule(wrapper, interval, timeUnit));
}    
READ ALSO
Есть ли преимущества в использовании числа вместо типа bool в Posgresql?

Есть ли преимущества в использовании числа вместо типа bool в Posgresql?

Несколько раз встречал в таблицах базы, относящейся к веб-приложению на Java, столбцы, играющие роль флага, но имеющие не привычный тип bool, а smallint...

77
Exception in thread &quot;main&quot; java.util.InputMismatchException. Не могу правильно реализовать if (action.equals(&quot;back&quot;)){continue;}

Exception in thread "main" java.util.InputMismatchException. Не могу правильно реализовать if (action.equals("back")){continue;}

Похоже ошибка в неправильном использовании if (actionequals("back")){continue;}

272