Временная задача Java истекает через некоторое время

#java #multithreading #timer #scheduling #timertask

#java #многопоточность #таймер #планирование #временная задача

Вопрос:

У меня есть временная задача, которая выполняется периодически, но иногда она застревает (не завершается сбоем или не выдает никаких исключений).

Следовательно, следующая итерация этой задачи не запускается, поскольку предыдущая застряла.

Я хочу, чтобы задача :

  1. Либо ТАЙМ-АУТ через некоторое время (чтобы можно было начать следующую итерацию).
  2. Или следующая итерация для запуска, даже если выполняется предыдущая, и это принудительно отменяет любую предыдущую запущенную задачу.

Ниже приведен мой код :

     private static Timer timer = new Timer();

    private static TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {

            try{
                aSeparateMethodWhichGetsStuckOccasionally();

            }catch (Exception exception){
                logger.info(">>> Exception : "   exception);
            }

        }
    };
    
    public static void scheduleTask() {
        
        initialDelay = 600000;
        gap = 600000;

        timer.scheduleAtFixedRate(timerTask, initialDelay, gap);
    }
  

Комментарии:

1. Не было бы лучше, если бы вы приступили к причинам, по которым ваши задачи застревают, и обратились к ним вместо того, чтобы накапливать там еще больше материала, который также может застрять?

Ответ №1:

Во-первых, вы должны написать aSeparateMethodWhichGetsStuckOccasionally() так, чтобы он мог правильно реагировать на прерывания. Прерывания — это единственный способ остановить многие операции.

Если этот метод перехвачен InterruptedException , полностью удалите try / catch и добавьте throws InterruptedException в объявление метода. Если этот метод содержит какие-либо catch (Exception) предложения, вы должны либо проверить InterruptedException и завершить в таком случае, либо, что еще лучше, изменить предложение, чтобы перехватывать только те исключения, которые вам абсолютно необходимо перехватить, не включая InterruptedException . (Перехват Exception — плохая практика. Большинство непроверенных исключений существуют для выявления ошибок программиста, которые следует исправлять, а не скрывать. Исключение NullPointerException и исключение IndexOutOfBoundsException являются примерами таких исключений.)

Это позволит прервать метод. Затем вы можете использовать ExecutorService.invokeAll, чтобы установить для него тайм-аут:

 private static final ExecutorService executor =
    Executors.newSingleThreadExecutor();

public static TimerTask timerTask = new TimerTask() {
    @Override
    public void run() {
        try {

            Callable<Void> subtask = () -> {
                aSeparateMethodWhichGetsStuckOccasionally();
                return null;
            };

            List<Future<Void>> futures =
                executor.invokeAll(Collections.singleton(subtask),
                    gap, TimeUnit.MILLISECONDS);

            Future<?> future = futures.get(0);
            if (!future.isCancelled()) {
                // Check if subtask threw an exception.
                future.get();
            }

        } catch (Exception exception) {
            logger.log(Level.INFO, ">>> Exception: "   exception, exception);
        }
    }
};