использование ScheduledExecutorService, чтобы запуститься и остановить таймер

От моих чтений кажется, что ScheduledExecutorService является правильным способом запустить и остановить таймеры в Java.

Я должен портировать некоторый код, который запускает и останавливает таймер. Это не периодический таймер. Этот код, останавливает таймер прежде, чем запустить его. Так, эффективно каждый запуск является действительно перезапуском (). Я ищу правильный способ сделать это использование ScheduledExecutorService. Вот то, что я придумал. При поиске комментариев и понимания на вещах я отсутствую:

ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> _TimerFuture = null;

private boolean startTimer() {
    try {
        if (_TimerFuture != null) {
            //cancel execution of the future task (TimerPopTask())
            //If task is already running, do not interrupt it.
            _TimerFuture.cancel(false);
        }

        _TimerFuture = _Timer.schedule(new TimerPopTask(), 
                                       TIMER_IN_SECONDS, 
                                       TimeUnit.SECONDS);
        return true;
    } catch (Exception e) {
        return false;
    }
}

private boolean stopTimer() {
    try {
        if (_TimerFuture != null) {
            //cancel execution of the future task (TimerPopTask())
            //If task is already running, interrupt it here.
            _TimerFuture.cancel(true);
        }

        return true;
    } catch (Exception e) {
        return false;
    }
}

private class TimerPopTask implements Runnable  {  
    public void run ()   {  
        TimerPopped();
    }  
}

public void TimerPopped () {
    //Do Something
}

tia, рубль

5
задан rouble 23 June 2010 в 19:43
поделиться

1 ответ

Это похоже на проблему:

private boolean startTimer() {
    // ......
        if (_TimerFuture != null) {
            _TimerFuture.cancel(false);
        }

        _TimerFuture = _Timer.schedule(new TimerPopTask(), 
                                       TIMER_IN_SECONDS, 
                                       TimeUnit.SECONDS);
    // ......
}

Поскольку вы передаете false для отмены, старый _TimerFuture может не отмениться, если задача уже запущена. В любом случае будет создана новая (но она не будет выполняться одновременно, поскольку ваш ExecutorService имеет фиксированный размер пула потоков, равный 1). В любом случае, это не похоже на желаемое поведение перезапуска таймера при вызове startTimer().

Я бы немного переработал архитектуру. Я бы сделал экземпляр TimerPopTask тем, что вы "отменяете", и оставил бы ScheduledFutures в покое после их создания:

private class TimerPopTask implements Runnable  {
    //volatile for thread-safety
    private volatile boolean isActive = true;  
    public void run ()   {  
        if (isActive){
            TimerPopped();
        }
    }  
    public void deactivate(){
        isActive = false;
    }
}

затем я бы сохранил экземпляр TimerPopTask, а не экземпляр ScheduledFuture и изменил бы метод startTimer таким образом:

private TimerPopTask timerPopTask;

private boolean startTimer() {
    try {
        if (timerPopTask != null) {
            timerPopTask.deactivate();
        }

        timerPopTask = new TimerPopTask();
        _Timer.schedule(timerPopTask, 
                        TIMER_IN_SECONDS, 
                        TimeUnit.SECONDS);
        return true;
    } catch (Exception e) {
        return false;
    }
}

(Аналогичная модификация метода stopTimer(). )

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

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5);

Вы можете использовать гибридный подход, сохраняя ссылки как на текущий TimerPopTask, как я описал, так и на текущий ScheduledFuture и прилагая максимальные усилия для его отмены и освобождения потока, если это возможно, понимая, что отмена не гарантирована.

(Примечание: все это предполагает, что вызовы методов startTimer() и stopTimer() ограничены одним главным потоком, и только экземпляры TimerPopTask разделяются между потоками. В противном случае вам понадобятся дополнительные меры защиты.)

.
3
ответ дан 15 December 2019 в 06:15
поделиться
Другие вопросы по тегам:

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