#java #multithreading #timer #scheduling #timertask
#java #многопоточность #таймер #планирование #временная задача
Вопрос:
У меня есть временная задача, которая выполняется периодически, но иногда она застревает (не завершается сбоем или не выдает никаких исключений).
Следовательно, следующая итерация этой задачи не запускается, поскольку предыдущая застряла.
Я хочу, чтобы задача :
- Либо ТАЙМ-АУТ через некоторое время (чтобы можно было начать следующую итерацию).
- Или следующая итерация для запуска, даже если выполняется предыдущая, и это принудительно отменяет любую предыдущую запущенную задачу.
Ниже приведен мой код :
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);
}
}
};