Почему Java scheduleWithFixedDelay работает с Runnable, но не с FutureTaskзавернуть работающий? - PullRequest
6 голосов
/ 07 июля 2010

Почему Java scheduleWithFixedDelay работает с Runnable, но не с FutureTask, обертывающим runnable?

Это довольно легко показать с помощью двух разных примеров кода:

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-секундными интервалами.

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

Ответы [ 2 ]

13 голосов
/ 07 июля 2010

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

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

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

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

3 голосов
/ 07 июля 2010

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

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

...