Почему scheduleWithFixedDelay Java работает с Выполнимым, но не FutureTask<?> обертывание выполнимого?

Почему scheduleWithFixedDelay Java работает с Выполнимым, но не FutureTask, переносящим выполнимое?

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

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(new FutureTask<Integer>(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                System.out.println("beep");
                return 1;
            }
        }), 1, 5, TimeUnit.SECONDS);

производит:

звуковой сигнал

Но приложение не выходит, это просто, кажется, ожидает.

но:

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    executorService.scheduleWithFixedDelay(new Runnable() {

        @Override
        public void run() {
            System.out.println("beep ");
        }
    }, 1, 5, TimeUnit.SECONDS);

производит:

подайте звуковой сигнал звуковой сигнал звукового сигнала звукового сигнала звукового сигнала

в 5-секундных интервалах.

Кажется, что существует некоторая блокировка, происходящая здесь, что я не могу определить.

6
задан Nathan Feger 7 July 2010 в 17:04
поделиться

2 ответа

Потому что вы как бы злоупотребляете FutureTask.

FutureTask - это "отменяемое асинхронное вычисление", согласно Javadocs, но более просторечно это обертывание определенного выполнения Runnable/Callable для обеспечения асинхронности. На самом деле я не понимал, что он реализует Runnable, пока не проверил только что - реализация run() "устанавливает это будущее в результат его вычислений".

Итак, что происходит в вашем первом примере: вы планируете задачу Future, ее метод run вызывается через 1 секунду и вычисляет результат вычислений (т.е. запускает встроенный Runnable). Когда этот метод завершается, FutureTask уже выполнилась и имеет свой конкретный результат - так что будущие вызовы run() не имеют смысла.

Я думаю, что основная проблема здесь в том, что, похоже, нет смысла планировать FutureTask напрямую, по крайней мере, так, как вы это делаете здесь. Если вы хотите, чтобы часть кода выполнялась каждые пять секунд, то вам определенно следует использовать второй подход. FutureTask воплощает в себе (единственный!) расчет; нет причин, почему вы хотите, чтобы он вызывался несколько раз, и на самом деле он специально кэширует результат, чтобы предотвратить это.

13
ответ дан 8 December 2019 в 14:39
поделиться

Вы не должны передавать объекты FutureTask в ScheduledExecutorService , вы должны передавать Runnable или Callable , который затем возвращает вам FutureTask . Тот факт, что FutureTask реализует интерфейс Runnable , кажется досадным недостатком дизайна, позволяющим передавать выходные данные обратно в качестве входных.

Что касается того, почему у вас такое поведение, возможно, это какое-то странное взаимодействие между компонентами и, вероятно, не определено.

3
ответ дан 8 December 2019 в 14:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: